From 90a46ad7d5647ae1dcfe24e8f9f7b46ce26de500 Mon Sep 17 00:00:00 2001 From: francopestilli Date: Fri, 24 Jul 2015 11:12:47 -0400 Subject: [PATCH] ENH: Adding files to the initial empty repository these fiels work on mac64 and LINUX64 --- compute/feComputeEvidence.m | 113 ++ compute/feFitModel.m | 100 + compute/feFitModel_OLD.m | 188 ++ compute/feGetConnectomeInfo.m | 50 + external/ByteSize.m | 36 + external/M_times_w.m | 24 + external/Mtransp_times_b_mex.mexmaci64 | Bin 0 -> 51028 bytes .../Mtransp_times_b_mex_v2015a_Intel.mexa64 | Bin 0 -> 47567 bytes external/bbnnls_GLNXA64.m | 281 +++ external/bbnnls_MACI64.m | 278 +++ external/bbnnls_OLD.m | 228 +++ external/emd-2005-02/Readme.txt | 30 + external/emd-2005-02/emd.m | 69 + external/emd-2005-02/gdf.m | 25 + external/emd-2005-02/gdm.m | 41 + external/emd-2005-02/test.m | 43 + external/solopt.m | 39 + .../tensor_toolbox_2.5/@ktensor/Contents.m | 36 + .../tensor_toolbox_2.5/@ktensor/arrange.m | 51 + .../tensor_toolbox_2.5/@ktensor/datadisp.m | 119 ++ external/tensor_toolbox_2.5/@ktensor/disp.m | 35 + .../tensor_toolbox_2.5/@ktensor/display.m | 20 + external/tensor_toolbox_2.5/@ktensor/double.m | 27 + external/tensor_toolbox_2.5/@ktensor/end.m | 32 + .../tensor_toolbox_2.5/@ktensor/extract.m | 30 + .../tensor_toolbox_2.5/@ktensor/fixsigns.m | 117 ++ .../tensor_toolbox_2.5/@ktensor/full (1).m | 26 + external/tensor_toolbox_2.5/@ktensor/full.m | 26 + .../tensor_toolbox_2.5/@ktensor/innerprod.m | 53 + .../tensor_toolbox_2.5/@ktensor/isequal.m | 28 + .../tensor_toolbox_2.5/@ktensor/ktensor.m | 89 + external/tensor_toolbox_2.5/@ktensor/minus.m | 45 + external/tensor_toolbox_2.5/@ktensor/mtimes.m | 30 + external/tensor_toolbox_2.5/@ktensor/mttkrp.m | 39 + .../tensor_toolbox_2.5/@ktensor/ncomponents.m | 20 + external/tensor_toolbox_2.5/@ktensor/ndims.m | 20 + external/tensor_toolbox_2.5/@ktensor/norm.m | 31 + .../tensor_toolbox_2.5/@ktensor/normalize.m | 97 + external/tensor_toolbox_2.5/@ktensor/nvecs.m | 65 + .../tensor_toolbox_2.5/@ktensor/permute.m | 34 + external/tensor_toolbox_2.5/@ktensor/plus.m | 37 + .../@ktensor/redistribute.m | 23 + external/tensor_toolbox_2.5/@ktensor/score.m | 173 ++ external/tensor_toolbox_2.5/@ktensor/size.m | 33 + .../tensor_toolbox_2.5/@ktensor/subsasgn.m | 49 + .../tensor_toolbox_2.5/@ktensor/subsref.m | 48 + external/tensor_toolbox_2.5/@ktensor/times.m | 34 + external/tensor_toolbox_2.5/@ktensor/tocell.m | 43 + .../tensor_toolbox_2.5/@ktensor/ttm (1).m | 110 ++ external/tensor_toolbox_2.5/@ktensor/ttm.m | 110 ++ external/tensor_toolbox_2.5/@ktensor/ttv.m | 77 + external/tensor_toolbox_2.5/@ktensor/uminus.m | 18 + external/tensor_toolbox_2.5/@ktensor/uplus.m | 19 + .../tensor_toolbox_2.5/@sptenmat/Contents.m | 18 + external/tensor_toolbox_2.5/@sptenmat/aatx.m | 39 + external/tensor_toolbox_2.5/@sptenmat/disp.m | 66 + .../tensor_toolbox_2.5/@sptenmat/display.m | 20 + .../tensor_toolbox_2.5/@sptenmat/double.m | 26 + external/tensor_toolbox_2.5/@sptenmat/end.m | 24 + external/tensor_toolbox_2.5/@sptenmat/full.m | 30 + external/tensor_toolbox_2.5/@sptenmat/nnz.m | 20 + external/tensor_toolbox_2.5/@sptenmat/norm.m | 22 + external/tensor_toolbox_2.5/@sptenmat/size.m | 33 + .../tensor_toolbox_2.5/@sptenmat/sptenmat.m | 244 +++ .../tensor_toolbox_2.5/@sptenmat/subsasgn.m | 70 + .../tensor_toolbox_2.5/@sptenmat/subsref.m | 43 + external/tensor_toolbox_2.5/@sptenmat/tsize.m | 36 + .../tensor_toolbox_2.5/@sptenmat/uminus.m | 18 + external/tensor_toolbox_2.5/@sptenmat/uplus.m | 19 + .../tensor_toolbox_2.5/@sptensor/Contents.m | 55 + external/tensor_toolbox_2.5/@sptensor/and.m | 58 + .../tensor_toolbox_2.5/@sptensor/collapse.m | 71 + .../tensor_toolbox_2.5/@sptensor/contract.m | 60 + .../tensor_toolbox_2.5/@sptensor/ctranspose.m | 18 + external/tensor_toolbox_2.5/@sptensor/disp.m | 85 + .../tensor_toolbox_2.5/@sptensor/display.m | 20 + .../tensor_toolbox_2.5/@sptensor/divide.m | 37 + .../tensor_toolbox_2.5/@sptensor/double.m | 21 + .../tensor_toolbox_2.5/@sptensor/elemfun.m | 41 + external/tensor_toolbox_2.5/@sptensor/end.m | 24 + external/tensor_toolbox_2.5/@sptensor/eq.m | 88 + external/tensor_toolbox_2.5/@sptensor/find.m | 27 + external/tensor_toolbox_2.5/@sptensor/full.m | 35 + external/tensor_toolbox_2.5/@sptensor/ge.m | 71 + external/tensor_toolbox_2.5/@sptensor/gt.m | 74 + .../tensor_toolbox_2.5/@sptensor/innerprod.m | 59 + .../tensor_toolbox_2.5/@sptensor/isequal.m | 32 + .../tensor_toolbox_2.5/@sptensor/ldivide.m | 21 + external/tensor_toolbox_2.5/@sptensor/le.m | 91 + external/tensor_toolbox_2.5/@sptensor/lt.m | 88 + external/tensor_toolbox_2.5/@sptensor/minus.m | 56 + .../tensor_toolbox_2.5/@sptensor/mldivide.m | 37 + .../tensor_toolbox_2.5/@sptensor/mrdivide.m | 37 + .../tensor_toolbox_2.5/@sptensor/mtimes.m | 35 + .../tensor_toolbox_2.5/@sptensor/mttkrp.m | 44 + external/tensor_toolbox_2.5/@sptensor/ndims.m | 24 + external/tensor_toolbox_2.5/@sptensor/ne.m | 82 + external/tensor_toolbox_2.5/@sptensor/nnz.m | 24 + external/tensor_toolbox_2.5/@sptensor/norm.m | 22 + external/tensor_toolbox_2.5/@sptensor/not.m | 28 + external/tensor_toolbox_2.5/@sptensor/nvecs.m | 62 + external/tensor_toolbox_2.5/@sptensor/ones.m | 21 + external/tensor_toolbox_2.5/@sptensor/or.m | 45 + .../tensor_toolbox_2.5/@sptensor/permute.m | 37 + external/tensor_toolbox_2.5/@sptensor/plus.m | 56 + .../@sptensor/private/allsubs.m | 34 + .../@sptensor/private/extract.m | 47 + .../@sptensor/private/irenumber.m | 35 + .../@sptensor/private/renumber.m | 52 + .../@sptensor/private/subdims.m | 63 + .../tensor_toolbox_2.5/@sptensor/rdivide.m | 107 ++ .../tensor_toolbox_2.5/@sptensor/reshape.m | 44 + external/tensor_toolbox_2.5/@sptensor/scale.m | 50 + external/tensor_toolbox_2.5/@sptensor/size.m | 26 + .../tensor_toolbox_2.5/@sptensor/spmatrix.m | 30 + .../tensor_toolbox_2.5/@sptensor/sptensor.m | 250 +++ .../tensor_toolbox_2.5/@sptensor/squeeze.m | 45 + .../tensor_toolbox_2.5/@sptensor/subsasgn.m | 317 ++++ .../tensor_toolbox_2.5/@sptensor/subsref.m | 159 ++ external/tensor_toolbox_2.5/@sptensor/times.m | 70 + .../tensor_toolbox_2.5/@sptensor/transpose.m | 18 + external/tensor_toolbox_2.5/@sptensor/ttm.m | 134 ++ external/tensor_toolbox_2.5/@sptensor/ttt.m | 171 ++ external/tensor_toolbox_2.5/@sptensor/ttv.m | 104 ++ .../tensor_toolbox_2.5/@sptensor/uminus.m | 18 + external/tensor_toolbox_2.5/@sptensor/uplus.m | 19 + external/tensor_toolbox_2.5/@sptensor/xor.m | 52 + .../tensor_toolbox_2.5/@tenmat/Contents.m | 19 + .../tensor_toolbox_2.5/@tenmat/ctranspose.m | 23 + external/tensor_toolbox_2.5/@tenmat/disp.m | 41 + external/tensor_toolbox_2.5/@tenmat/display.m | 18 + external/tensor_toolbox_2.5/@tenmat/double.m | 18 + external/tensor_toolbox_2.5/@tenmat/end.m | 24 + external/tensor_toolbox_2.5/@tenmat/minus.m | 38 + external/tensor_toolbox_2.5/@tenmat/mtimes.m | 62 + external/tensor_toolbox_2.5/@tenmat/norm.m | 21 + external/tensor_toolbox_2.5/@tenmat/plus.m | 38 + external/tensor_toolbox_2.5/@tenmat/size.m | 31 + .../tensor_toolbox_2.5/@tenmat/subsasgn.m | 33 + external/tensor_toolbox_2.5/@tenmat/subsref.m | 44 + external/tensor_toolbox_2.5/@tenmat/tenmat.m | 182 ++ external/tensor_toolbox_2.5/@tenmat/tsize.m | 33 + external/tensor_toolbox_2.5/@tenmat/uminus.m | 18 + external/tensor_toolbox_2.5/@tenmat/uplus.m | 19 + .../tensor_toolbox_2.5/@tensor/Contents.m | 56 + external/tensor_toolbox_2.5/@tensor/and.m | 18 + .../tensor_toolbox_2.5/@tensor/collapse.m | 76 + .../tensor_toolbox_2.5/@tensor/contract.m | 75 + .../tensor_toolbox_2.5/@tensor/ctranspose.m | 18 + external/tensor_toolbox_2.5/@tensor/disp.m | 50 + external/tensor_toolbox_2.5/@tensor/display.m | 20 + external/tensor_toolbox_2.5/@tensor/double.m | 20 + external/tensor_toolbox_2.5/@tensor/end.m | 24 + external/tensor_toolbox_2.5/@tensor/eq.m | 18 + external/tensor_toolbox_2.5/@tensor/find.m | 40 + external/tensor_toolbox_2.5/@tensor/full.m | 20 + external/tensor_toolbox_2.5/@tensor/ge.m | 18 + external/tensor_toolbox_2.5/@tensor/gt.m | 18 + .../tensor_toolbox_2.5/@tensor/innerprod.m | 42 + external/tensor_toolbox_2.5/@tensor/isequal.m | 29 + .../tensor_toolbox_2.5/@tensor/issymmetric.m | 88 + external/tensor_toolbox_2.5/@tensor/ldivide.m | 26 + external/tensor_toolbox_2.5/@tensor/le.m | 18 + external/tensor_toolbox_2.5/@tensor/lt.m | 18 + external/tensor_toolbox_2.5/@tensor/minus.m | 22 + .../tensor_toolbox_2.5/@tensor/mldivide.m | 31 + .../tensor_toolbox_2.5/@tensor/mrdivide.m | 31 + external/tensor_toolbox_2.5/@tensor/mtimes.m | 47 + external/tensor_toolbox_2.5/@tensor/mttkrp.m | 49 + external/tensor_toolbox_2.5/@tensor/ndims.m | 25 + external/tensor_toolbox_2.5/@tensor/ne.m | 18 + external/tensor_toolbox_2.5/@tensor/nnz.m | 18 + external/tensor_toolbox_2.5/@tensor/norm.m | 21 + external/tensor_toolbox_2.5/@tensor/not.m | 18 + external/tensor_toolbox_2.5/@tensor/nvecs.m | 58 + external/tensor_toolbox_2.5/@tensor/or.m | 18 + external/tensor_toolbox_2.5/@tensor/permute.m | 46 + external/tensor_toolbox_2.5/@tensor/plus.m | 22 + external/tensor_toolbox_2.5/@tensor/power.m | 18 + external/tensor_toolbox_2.5/@tensor/rdivide.m | 26 + external/tensor_toolbox_2.5/@tensor/reshape.m | 25 + external/tensor_toolbox_2.5/@tensor/scale.m | 71 + external/tensor_toolbox_2.5/@tensor/size.m | 38 + external/tensor_toolbox_2.5/@tensor/squeeze.m | 42 + .../tensor_toolbox_2.5/@tensor/subsasgn.m | 139 ++ external/tensor_toolbox_2.5/@tensor/subsref.m | 131 ++ .../tensor_toolbox_2.5/@tensor/symmetrize.m | 111 ++ external/tensor_toolbox_2.5/@tensor/tenfun.m | 132 ++ external/tensor_toolbox_2.5/@tensor/tensor.m | 123 ++ external/tensor_toolbox_2.5/@tensor/times.m | 26 + .../tensor_toolbox_2.5/@tensor/transpose.m | 18 + external/tensor_toolbox_2.5/@tensor/ttm.m | 118 ++ external/tensor_toolbox_2.5/@tensor/ttsv.m | 48 + external/tensor_toolbox_2.5/@tensor/ttt.m | 94 + external/tensor_toolbox_2.5/@tensor/ttv.m | 105 ++ external/tensor_toolbox_2.5/@tensor/uminus.m | 18 + external/tensor_toolbox_2.5/@tensor/uplus.m | 19 + external/tensor_toolbox_2.5/@tensor/xor.m | 18 + .../tensor_toolbox_2.5/@ttensor/Contents.m | 24 + external/tensor_toolbox_2.5/@ttensor/disp.m | 35 + .../tensor_toolbox_2.5/@ttensor/display.m | 18 + external/tensor_toolbox_2.5/@ttensor/double.m | 20 + external/tensor_toolbox_2.5/@ttensor/end.m | 23 + external/tensor_toolbox_2.5/@ttensor/full.m | 30 + .../tensor_toolbox_2.5/@ttensor/innerprod.m | 68 + .../tensor_toolbox_2.5/@ttensor/isequal.m | 19 + external/tensor_toolbox_2.5/@ttensor/mtimes.m | 24 + external/tensor_toolbox_2.5/@ttensor/mttkrp.m | 40 + external/tensor_toolbox_2.5/@ttensor/ndims.m | 20 + external/tensor_toolbox_2.5/@ttensor/norm.m | 29 + external/tensor_toolbox_2.5/@ttensor/nvecs.m | 85 + .../tensor_toolbox_2.5/@ttensor/permute.m | 36 + external/tensor_toolbox_2.5/@ttensor/size.m | 33 + .../tensor_toolbox_2.5/@ttensor/subsasgn.m | 49 + .../tensor_toolbox_2.5/@ttensor/subsref.m | 44 + .../tensor_toolbox_2.5/@ttensor/ttensor.m | 92 + external/tensor_toolbox_2.5/@ttensor/ttm.m | 107 ++ external/tensor_toolbox_2.5/@ttensor/ttv.m | 81 + external/tensor_toolbox_2.5/@ttensor/uminus.m | 18 + external/tensor_toolbox_2.5/@ttensor/uplus.m | 18 + external/tensor_toolbox_2.5/COPYRIGHT.txt | 35 + external/tensor_toolbox_2.5/Contents.m | 235 +++ external/tensor_toolbox_2.5/INSTALL.txt | 29 + external/tensor_toolbox_2.5/LICENSE.txt | 94 + external/tensor_toolbox_2.5/RELEASE_NOTES.txt | 286 +++ external/tensor_toolbox_2.5/cp_als.m | 187 ++ external/tensor_toolbox_2.5/cp_apr.m | 242 +++ external/tensor_toolbox_2.5/cp_nmu.m | 171 ++ external/tensor_toolbox_2.5/cp_opt.m | 137 ++ external/tensor_toolbox_2.5/cp_wopt.m | 148 ++ external/tensor_toolbox_2.5/create_guess.m | 155 ++ external/tensor_toolbox_2.5/create_problem.m | 376 ++++ .../tensor_toolbox_2.5/doc/A1_tensor_doc.m | 194 ++ .../tensor_toolbox_2.5/doc/A2_sptensor_doc.m | 171 ++ .../tensor_toolbox_2.5/doc/B1_tenmat_doc.m | 81 + .../tensor_toolbox_2.5/doc/B2_sptenmat_doc.m | 88 + .../tensor_toolbox_2.5/doc/C_ttensor_doc.m | 77 + .../tensor_toolbox_2.5/doc/D_ktensor_doc.m | 147 ++ .../tensor_toolbox_2.5/doc/M1_multiply_doc.m | 274 +++ .../doc/M2_identities_doc_future.m | 236 +++ external/tensor_toolbox_2.5/doc/N_nvecs_doc.m | 45 + .../doc/Q_collapse_scale_doc.m | 60 + .../doc/S_test_problems_doc.m | 266 +++ .../doc/T1_algorithms_doc.m | 35 + .../doc/T2_opt_algorithms_doc.m | 95 + .../doc/T3_wopt_algorithms_doc.m | 121 ++ .../tensor_toolbox_2.5/doc/T4_cpapr_doc.m | 41 + .../tensor_toolbox_2.5/doc/V_SSHOPM_doc.m | 32 + .../doc/html/A1_tensor_doc.html | 908 +++++++++ .../doc/html/A2_sptensor_doc.html | 753 ++++++++ .../doc/html/B1_tenmat_doc.html | 481 +++++ .../doc/html/B2_sptenmat_doc.html | 561 ++++++ .../doc/html/C_ttensor_doc.html | 621 +++++++ .../doc/html/C_ttensor_doc_eq15566.png | Bin 0 -> 2454 bytes .../doc/html/D_ktensor_doc.html | 776 ++++++++ .../doc/html/D_ktensor_doc_eq09466.png | Bin 0 -> 2171 bytes .../doc/html/D_ktensor_doc_eq51104.png | Bin 0 -> 2497 bytes .../doc/html/D_ktensor_doc_eq64665.png | Bin 0 -> 3448 bytes .../doc/html/D_ktensor_doc_eq81501.png | Bin 0 -> 2517 bytes .../doc/html/M1_multiply_doc.html | 1509 +++++++++++++++ .../doc/html/N_nvecs_doc.html | 273 +++ .../doc/html/Q_collapse_scale_doc.html | 448 +++++ .../doc/html/S_test_problems_doc.html | 682 +++++++ .../doc/html/T1_algorithms_doc.html | 449 +++++ .../doc/html/T2_opt_algorithms_doc.html | 282 +++ .../doc/html/T3_wopt_algorithms_doc.html | 354 ++++ .../doc/html/T4_cpapr_doc.html | 157 ++ .../doc/html/V_SSHOPM_doc.html | 122 ++ .../doc/html/V_SSHOPM_doc.png | Bin 0 -> 1669 bytes .../doc/html/V_SSHOPM_doc_01.png | Bin 0 -> 3506 bytes .../doc/html/V_SSHOPM_doc_02.png | Bin 0 -> 3521 bytes .../doc/images/Workspace.png | Bin 0 -> 4184 bytes .../doc/images/banner-background.jpg | Bin 0 -> 7479 bytes .../tensor_toolbox_2.5/doc/images/logo.gif | Bin 0 -> 5695 bytes external/tensor_toolbox_2.5/export_data.m | 85 + external/tensor_toolbox_2.5/helpindex.xml | 6 + external/tensor_toolbox_2.5/helptoc.xml | 43 + external/tensor_toolbox_2.5/import_data.m | 69 + external/tensor_toolbox_2.5/info.xml | 25 + external/tensor_toolbox_2.5/khatrirao.m | 95 + external/tensor_toolbox_2.5/met/Contents.m | 8 + external/tensor_toolbox_2.5/met/ttm_me.m | 157 ++ external/tensor_toolbox_2.5/met/ttm_me_mem.m | 89 + .../tensor_toolbox_2.5/met/ttm_me_partition.m | 38 + external/tensor_toolbox_2.5/met/tucker_me.m | 154 ++ .../tensor_toolbox_2.5/met/tucker_me_test.m | 105 ++ external/tensor_toolbox_2.5/parafac_als.m | 32 + external/tensor_toolbox_2.5/sptendiag.m | 39 + external/tensor_toolbox_2.5/sptenrand.m | 63 + external/tensor_toolbox_2.5/sshopm.m | 173 ++ external/tensor_toolbox_2.5/sshopmc.m | 175 ++ external/tensor_toolbox_2.5/tendiag.m | 39 + external/tensor_toolbox_2.5/teneye.m | 48 + external/tensor_toolbox_2.5/tenones.m | 34 + external/tensor_toolbox_2.5/tenrand.m | 30 + .../tensor_toolbox_product_page.html | 228 +++ external/tensor_toolbox_2.5/tenzeros.m | 41 + external/tensor_toolbox_2.5/tt_RandOrthMat.m | 50 + .../tensor_toolbox_2.5/tt_assignment_type.m | 28 + external/tensor_toolbox_2.5/tt_ccong.m | 27 + external/tensor_toolbox_2.5/tt_combinator.m | 392 ++++ external/tensor_toolbox_2.5/tt_cp_fg.m | 88 + external/tensor_toolbox_2.5/tt_cp_fun.m | 30 + .../tensor_toolbox_2.5/tt_cp_vec_to_fac.m | 35 + external/tensor_toolbox_2.5/tt_cp_wfg.m | 53 + .../tensor_toolbox_2.5/tt_cp_wfg_sparse.m | 99 + .../tt_cp_wfg_sparse_setup.m | 26 + external/tensor_toolbox_2.5/tt_cp_wfun.m | 58 + .../tt_create_missing_data_pattern.m | 82 + external/tensor_toolbox_2.5/tt_dimscheck.m | 78 + external/tensor_toolbox_2.5/tt_fac_to_vec.m | 38 + external/tensor_toolbox_2.5/tt_ind2sub.m | 32 + external/tensor_toolbox_2.5/tt_intvec2str.m | 21 + .../tensor_toolbox_2.5/tt_loglikelihood.m | 41 + .../tensor_toolbox_2.5/tt_matrix2cellstr.m | 22 + external/tensor_toolbox_2.5/tt_size2str.m | 26 + external/tensor_toolbox_2.5/tt_sizecheck.m | 35 + external/tensor_toolbox_2.5/tt_sub2ind.m | 29 + external/tensor_toolbox_2.5/tt_subscheck.m | 39 + external/tensor_toolbox_2.5/tt_subsubsref.m | 21 + external/tensor_toolbox_2.5/tt_valscheck.m | 31 + external/tensor_toolbox_2.5/tucker_als.m | 158 ++ fe/feBuildDictionaries.m | 57 + fe/feConnectomeBuildModel.m | 210 +++ fe/feConnectomeInit.m | 130 ++ fe/feConnectomeSetDwi.m | 60 + fe/feCreate.m | 53 + fe/feGet.m | 1627 ++++++++++++++++ fe/feGetOLD.m | 1628 +++++++++++++++++ fe/feGetRep.m | 873 +++++++++ fe/feGetRepOLD.m | 873 +++++++++ fe/feSet.m | 197 ++ scripts/life_demo.m | 415 +++++ utility/fefgGet.m | 813 ++++++++ 334 files changed, 34344 insertions(+) create mode 100755 compute/feComputeEvidence.m create mode 100755 compute/feFitModel.m create mode 100755 compute/feFitModel_OLD.m create mode 100755 compute/feGetConnectomeInfo.m create mode 100755 external/ByteSize.m create mode 100755 external/M_times_w.m create mode 100755 external/Mtransp_times_b_mex.mexmaci64 create mode 100755 external/Mtransp_times_b_mex_v2015a_Intel.mexa64 create mode 100755 external/bbnnls_GLNXA64.m create mode 100755 external/bbnnls_MACI64.m create mode 100755 external/bbnnls_OLD.m create mode 100755 external/emd-2005-02/Readme.txt create mode 100755 external/emd-2005-02/emd.m create mode 100755 external/emd-2005-02/gdf.m create mode 100755 external/emd-2005-02/gdm.m create mode 100755 external/emd-2005-02/test.m create mode 100755 external/solopt.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/Contents.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/arrange.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/datadisp.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/disp.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/display.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/double.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/end.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/extract.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/fixsigns.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/full (1).m create mode 100755 external/tensor_toolbox_2.5/@ktensor/full.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/innerprod.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/isequal.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/ktensor.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/minus.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/mtimes.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/mttkrp.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/ncomponents.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/ndims.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/norm.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/normalize.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/nvecs.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/permute.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/plus.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/redistribute.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/score.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/size.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/subsasgn.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/subsref.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/times.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/tocell.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/ttm (1).m create mode 100755 external/tensor_toolbox_2.5/@ktensor/ttm.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/ttv.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/uminus.m create mode 100755 external/tensor_toolbox_2.5/@ktensor/uplus.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/Contents.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/aatx.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/disp.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/display.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/double.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/end.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/full.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/nnz.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/norm.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/size.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/sptenmat.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/subsasgn.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/subsref.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/tsize.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/uminus.m create mode 100755 external/tensor_toolbox_2.5/@sptenmat/uplus.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/Contents.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/and.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/collapse.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/contract.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/ctranspose.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/disp.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/display.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/divide.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/double.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/elemfun.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/end.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/eq.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/find.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/full.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/ge.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/gt.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/innerprod.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/isequal.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/ldivide.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/le.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/lt.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/minus.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/mldivide.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/mrdivide.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/mtimes.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/mttkrp.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/ndims.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/ne.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/nnz.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/norm.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/not.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/nvecs.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/ones.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/or.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/permute.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/plus.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/private/allsubs.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/private/extract.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/private/irenumber.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/private/renumber.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/private/subdims.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/rdivide.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/reshape.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/scale.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/size.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/spmatrix.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/sptensor.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/squeeze.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/subsasgn.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/subsref.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/times.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/transpose.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/ttm.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/ttt.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/ttv.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/uminus.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/uplus.m create mode 100755 external/tensor_toolbox_2.5/@sptensor/xor.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/Contents.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/ctranspose.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/disp.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/display.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/double.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/end.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/minus.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/mtimes.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/norm.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/plus.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/size.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/subsasgn.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/subsref.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/tenmat.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/tsize.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/uminus.m create mode 100755 external/tensor_toolbox_2.5/@tenmat/uplus.m create mode 100755 external/tensor_toolbox_2.5/@tensor/Contents.m create mode 100755 external/tensor_toolbox_2.5/@tensor/and.m create mode 100755 external/tensor_toolbox_2.5/@tensor/collapse.m create mode 100755 external/tensor_toolbox_2.5/@tensor/contract.m create mode 100755 external/tensor_toolbox_2.5/@tensor/ctranspose.m create mode 100755 external/tensor_toolbox_2.5/@tensor/disp.m create mode 100755 external/tensor_toolbox_2.5/@tensor/display.m create mode 100755 external/tensor_toolbox_2.5/@tensor/double.m create mode 100755 external/tensor_toolbox_2.5/@tensor/end.m create mode 100755 external/tensor_toolbox_2.5/@tensor/eq.m create mode 100755 external/tensor_toolbox_2.5/@tensor/find.m create mode 100755 external/tensor_toolbox_2.5/@tensor/full.m create mode 100755 external/tensor_toolbox_2.5/@tensor/ge.m create mode 100755 external/tensor_toolbox_2.5/@tensor/gt.m create mode 100755 external/tensor_toolbox_2.5/@tensor/innerprod.m create mode 100755 external/tensor_toolbox_2.5/@tensor/isequal.m create mode 100755 external/tensor_toolbox_2.5/@tensor/issymmetric.m create mode 100755 external/tensor_toolbox_2.5/@tensor/ldivide.m create mode 100755 external/tensor_toolbox_2.5/@tensor/le.m create mode 100755 external/tensor_toolbox_2.5/@tensor/lt.m create mode 100755 external/tensor_toolbox_2.5/@tensor/minus.m create mode 100755 external/tensor_toolbox_2.5/@tensor/mldivide.m create mode 100755 external/tensor_toolbox_2.5/@tensor/mrdivide.m create mode 100755 external/tensor_toolbox_2.5/@tensor/mtimes.m create mode 100755 external/tensor_toolbox_2.5/@tensor/mttkrp.m create mode 100755 external/tensor_toolbox_2.5/@tensor/ndims.m create mode 100755 external/tensor_toolbox_2.5/@tensor/ne.m create mode 100755 external/tensor_toolbox_2.5/@tensor/nnz.m create mode 100755 external/tensor_toolbox_2.5/@tensor/norm.m create mode 100755 external/tensor_toolbox_2.5/@tensor/not.m create mode 100755 external/tensor_toolbox_2.5/@tensor/nvecs.m create mode 100755 external/tensor_toolbox_2.5/@tensor/or.m create mode 100755 external/tensor_toolbox_2.5/@tensor/permute.m create mode 100755 external/tensor_toolbox_2.5/@tensor/plus.m create mode 100755 external/tensor_toolbox_2.5/@tensor/power.m create mode 100755 external/tensor_toolbox_2.5/@tensor/rdivide.m create mode 100755 external/tensor_toolbox_2.5/@tensor/reshape.m create mode 100755 external/tensor_toolbox_2.5/@tensor/scale.m create mode 100755 external/tensor_toolbox_2.5/@tensor/size.m create mode 100755 external/tensor_toolbox_2.5/@tensor/squeeze.m create mode 100755 external/tensor_toolbox_2.5/@tensor/subsasgn.m create mode 100755 external/tensor_toolbox_2.5/@tensor/subsref.m create mode 100755 external/tensor_toolbox_2.5/@tensor/symmetrize.m create mode 100755 external/tensor_toolbox_2.5/@tensor/tenfun.m create mode 100755 external/tensor_toolbox_2.5/@tensor/tensor.m create mode 100755 external/tensor_toolbox_2.5/@tensor/times.m create mode 100755 external/tensor_toolbox_2.5/@tensor/transpose.m create mode 100755 external/tensor_toolbox_2.5/@tensor/ttm.m create mode 100755 external/tensor_toolbox_2.5/@tensor/ttsv.m create mode 100755 external/tensor_toolbox_2.5/@tensor/ttt.m create mode 100755 external/tensor_toolbox_2.5/@tensor/ttv.m create mode 100755 external/tensor_toolbox_2.5/@tensor/uminus.m create mode 100755 external/tensor_toolbox_2.5/@tensor/uplus.m create mode 100755 external/tensor_toolbox_2.5/@tensor/xor.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/Contents.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/disp.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/display.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/double.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/end.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/full.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/innerprod.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/isequal.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/mtimes.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/mttkrp.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/ndims.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/norm.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/nvecs.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/permute.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/size.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/subsasgn.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/subsref.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/ttensor.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/ttm.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/ttv.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/uminus.m create mode 100755 external/tensor_toolbox_2.5/@ttensor/uplus.m create mode 100755 external/tensor_toolbox_2.5/COPYRIGHT.txt create mode 100755 external/tensor_toolbox_2.5/Contents.m create mode 100755 external/tensor_toolbox_2.5/INSTALL.txt create mode 100755 external/tensor_toolbox_2.5/LICENSE.txt create mode 100755 external/tensor_toolbox_2.5/RELEASE_NOTES.txt create mode 100755 external/tensor_toolbox_2.5/cp_als.m create mode 100755 external/tensor_toolbox_2.5/cp_apr.m create mode 100755 external/tensor_toolbox_2.5/cp_nmu.m create mode 100755 external/tensor_toolbox_2.5/cp_opt.m create mode 100755 external/tensor_toolbox_2.5/cp_wopt.m create mode 100755 external/tensor_toolbox_2.5/create_guess.m create mode 100755 external/tensor_toolbox_2.5/create_problem.m create mode 100755 external/tensor_toolbox_2.5/doc/A1_tensor_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/A2_sptensor_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/B1_tenmat_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/B2_sptenmat_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/C_ttensor_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/D_ktensor_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/M1_multiply_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/M2_identities_doc_future.m create mode 100755 external/tensor_toolbox_2.5/doc/N_nvecs_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/Q_collapse_scale_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/S_test_problems_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/T1_algorithms_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/T2_opt_algorithms_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/T3_wopt_algorithms_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/T4_cpapr_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/V_SSHOPM_doc.m create mode 100755 external/tensor_toolbox_2.5/doc/html/A1_tensor_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/A2_sptensor_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/B1_tenmat_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/B2_sptenmat_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/C_ttensor_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/C_ttensor_doc_eq15566.png create mode 100755 external/tensor_toolbox_2.5/doc/html/D_ktensor_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq09466.png create mode 100755 external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq51104.png create mode 100755 external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq64665.png create mode 100755 external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq81501.png create mode 100755 external/tensor_toolbox_2.5/doc/html/M1_multiply_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/N_nvecs_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/Q_collapse_scale_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/S_test_problems_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/T1_algorithms_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/T2_opt_algorithms_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/T3_wopt_algorithms_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/T4_cpapr_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc.html create mode 100755 external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc.png create mode 100755 external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc_01.png create mode 100755 external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc_02.png create mode 100755 external/tensor_toolbox_2.5/doc/images/Workspace.png create mode 100755 external/tensor_toolbox_2.5/doc/images/banner-background.jpg create mode 100755 external/tensor_toolbox_2.5/doc/images/logo.gif create mode 100755 external/tensor_toolbox_2.5/export_data.m create mode 100755 external/tensor_toolbox_2.5/helpindex.xml create mode 100755 external/tensor_toolbox_2.5/helptoc.xml create mode 100755 external/tensor_toolbox_2.5/import_data.m create mode 100755 external/tensor_toolbox_2.5/info.xml create mode 100755 external/tensor_toolbox_2.5/khatrirao.m create mode 100755 external/tensor_toolbox_2.5/met/Contents.m create mode 100755 external/tensor_toolbox_2.5/met/ttm_me.m create mode 100755 external/tensor_toolbox_2.5/met/ttm_me_mem.m create mode 100755 external/tensor_toolbox_2.5/met/ttm_me_partition.m create mode 100755 external/tensor_toolbox_2.5/met/tucker_me.m create mode 100755 external/tensor_toolbox_2.5/met/tucker_me_test.m create mode 100755 external/tensor_toolbox_2.5/parafac_als.m create mode 100755 external/tensor_toolbox_2.5/sptendiag.m create mode 100755 external/tensor_toolbox_2.5/sptenrand.m create mode 100755 external/tensor_toolbox_2.5/sshopm.m create mode 100755 external/tensor_toolbox_2.5/sshopmc.m create mode 100755 external/tensor_toolbox_2.5/tendiag.m create mode 100755 external/tensor_toolbox_2.5/teneye.m create mode 100755 external/tensor_toolbox_2.5/tenones.m create mode 100755 external/tensor_toolbox_2.5/tenrand.m create mode 100755 external/tensor_toolbox_2.5/tensor_toolbox_product_page.html create mode 100755 external/tensor_toolbox_2.5/tenzeros.m create mode 100755 external/tensor_toolbox_2.5/tt_RandOrthMat.m create mode 100755 external/tensor_toolbox_2.5/tt_assignment_type.m create mode 100755 external/tensor_toolbox_2.5/tt_ccong.m create mode 100755 external/tensor_toolbox_2.5/tt_combinator.m create mode 100755 external/tensor_toolbox_2.5/tt_cp_fg.m create mode 100755 external/tensor_toolbox_2.5/tt_cp_fun.m create mode 100755 external/tensor_toolbox_2.5/tt_cp_vec_to_fac.m create mode 100755 external/tensor_toolbox_2.5/tt_cp_wfg.m create mode 100755 external/tensor_toolbox_2.5/tt_cp_wfg_sparse.m create mode 100755 external/tensor_toolbox_2.5/tt_cp_wfg_sparse_setup.m create mode 100755 external/tensor_toolbox_2.5/tt_cp_wfun.m create mode 100755 external/tensor_toolbox_2.5/tt_create_missing_data_pattern.m create mode 100755 external/tensor_toolbox_2.5/tt_dimscheck.m create mode 100755 external/tensor_toolbox_2.5/tt_fac_to_vec.m create mode 100755 external/tensor_toolbox_2.5/tt_ind2sub.m create mode 100755 external/tensor_toolbox_2.5/tt_intvec2str.m create mode 100755 external/tensor_toolbox_2.5/tt_loglikelihood.m create mode 100755 external/tensor_toolbox_2.5/tt_matrix2cellstr.m create mode 100755 external/tensor_toolbox_2.5/tt_size2str.m create mode 100755 external/tensor_toolbox_2.5/tt_sizecheck.m create mode 100755 external/tensor_toolbox_2.5/tt_sub2ind.m create mode 100755 external/tensor_toolbox_2.5/tt_subscheck.m create mode 100755 external/tensor_toolbox_2.5/tt_subsubsref.m create mode 100755 external/tensor_toolbox_2.5/tt_valscheck.m create mode 100755 external/tensor_toolbox_2.5/tucker_als.m create mode 100755 fe/feBuildDictionaries.m create mode 100755 fe/feConnectomeBuildModel.m create mode 100755 fe/feConnectomeInit.m create mode 100755 fe/feConnectomeSetDwi.m create mode 100755 fe/feCreate.m create mode 100755 fe/feGet.m create mode 100755 fe/feGetOLD.m create mode 100755 fe/feGetRep.m create mode 100755 fe/feGetRepOLD.m create mode 100755 fe/feSet.m create mode 100755 scripts/life_demo.m create mode 100755 utility/fefgGet.m diff --git a/compute/feComputeEvidence.m b/compute/feComputeEvidence.m new file mode 100755 index 0000000..4ef954e --- /dev/null +++ b/compute/feComputeEvidence.m @@ -0,0 +1,113 @@ +function se = feComputeEvidence(rmse1,rmse2) +% Computes a series of distance metrics between two RMSE distribtions. +% +% Compute summary statistics on to characterize the lesion,: +% We compute: +% - The strength of evidence, namely the effect size of the lesion +% - The Kullback-Leibler Divergence +% - Jeffrey's Divergence +% - The Eath Mover's distance +% +% Copyright (2013-2014), Franco Pestilli, Stanford University, pestillifranco@gmail.com. + +% Prepare the distribution of errors and the histograms describing the +% erros. +se.nolesion.rmse.all = rmse1; +se.lesion.rmse.all = rmse2; +se.nolesion.rmse.mean = mean(se.nolesion.rmse.all); +se.lesion.rmse.mean = mean(se.lesion.rmse.all); + +% Histograms +se.xrange(1) = ceil(min([se.lesion.rmse.all se.nolesion.rmse.all])); +se.xrange(2) = floor(max([se.lesion.rmse.all se.nolesion.rmse.all])); +se.nbins = 60; +se.bins = linspace(se.xrange(1),se.xrange(2),se.nbins); +[se.lesion.hist, se.lesion.xhist] = hist(se.lesion.rmse.all, se.bins); +[se.nolesion.hist, se.nolesion.xhist] = hist(se.nolesion.rmse.all,se.bins); +se.lesion.hist = se.lesion.hist ./ sum(se.lesion.hist); +se.nolesion.hist = se.nolesion.hist ./ sum(se.nolesion.hist); + +% Kullback-Leibler Divergence +se.kl.name = sprintf('Kullback–Leibler divergence: http://en.wikipedia.org/wiki/Kullback-Leibler_divergence'); +tmp = se.nolesion.hist .* log2( (se.nolesion.hist) ./ (se.lesion.hist + eps) ); +se.kl.mean = nansum(tmp);clear tmp +se.kl.std = nan; + +% Jeffrey's divergence +se.j.name = sprintf('Jeffrey''s divergence: http://en.wikipedia.org/wiki/Divergence_(statistics)'); +tmp = se.nolesion.hist .* log2( (se.nolesion.hist) ./ ((se.lesion.hist + se.lesion.hist + eps)./2) ) + ... + se.lesion.hist .* log2( (se.lesion.hist) ./ ((se.lesion.hist + se.lesion.hist + eps)./2) ); +se.j.mean = nansum(tmp); clear tmp +se.j.std = nan; + +% Earth Mover's Distance: +% Note: This can be very slow and my require large amounts of memory for more than 1000 voxels +fprintf('[%s] Computing the Earth Mover''s distance... \n',mfilename) +se.em.name = sprintf('Earth Mover''s distance: http://en.wikipedia.org/wiki/Earth_mover''s_distance'); + +try +%if (exist('emd_mex.m','file') == 2) % Using Rubinov c-code fastest + pairwiseDist = zeros(size(se.lesion.xhist,2)); + for i=1:size(se.nolesion.xhist,2) + for j=1:size(se.lesion.xhist,2) + pairwiseDist(i,j) = abs(se.lesion.xhist(i)-se.nolesion.xhist(j)); + end + end + tmp_em = emd_mex(se.nolesion.hist,se.lesion.hist,pairwiseDist); +catch ME %else + fprintf('[%s] Cannot find compiled c-code for Earth Movers Distance.\nUsing the slower and less reliable MatLab implementation.',mfilename) + [~,tmp_em] = emd(se.nolesion.xhist',se.lesion.xhist',se.nolesion.hist',se.lesion.hist',@gdf); +end +se.em.mean = tmp_em; +se.em.std = nan; +clear tmp_emp + +% Strenght of evidence (effect size) +fprintf('[%s] Computing the Strength of Evidence... \n',mfilename) +se.s.name = sprintf('strength of evidence, d-prime: http://en.wikipedia.org/wiki/Effect_size'); +se.s.nboots = 5000; +se.s.nmontecarlo = 5; +se.s.nbins = 200; +sizeunlesioned = length(se.nolesion.rmse.all); +nullDistributionW = nan(se.s.nboots,se.s.nmontecarlo); +nullDistributionWO = nan(se.s.nboots,se.s.nmontecarlo); +min_x = floor(mean([se.nolesion.rmse.all]) - mean([se.nolesion.rmse.all])*.05); +max_x = ceil( mean([se.lesion.rmse.all]) + mean([se.lesion.rmse.all])*.05); + +for inm = 1:se.s.nmontecarlo + fprintf('.') + parfor ibt = 1:se.s.nboots + nullDistributionW(ibt,inm) = mean(randsample(se.nolesion.rmse.all, sizeunlesioned,true)); + nullDistributionWO(ibt,inm) = mean(randsample(se.lesion.rmse.all,sizeunlesioned,true)); + end + + % Distribution unlesioned + [y(:,inm),xhis] = hist(nullDistributionW(:,inm),linspace(min_x,max_x,se.s.nbins)); + y(:,inm) = y(:,inm)./sum(y(:,inm)); + + % Distribution lesioned + [woy(:,inm),woxhis] = hist(nullDistributionWO(:,inm),linspace(min_x,max_x,se.s.nbins)); + woy(:,inm) = woy(:,inm)./sum(woy(:,inm)); +end + +se.s.mean = mean(diff([mean(nullDistributionW,1); ... + mean(nullDistributionWO,1)])./sqrt(sum([std(nullDistributionW,[],1);std(nullDistributionWO,[],1)].^2,1))); +se.s.std = std(diff([mean(nullDistributionW,1); ... + mean(nullDistributionWO,1)])./sqrt(sum([std(nullDistributionW,[],1);std(nullDistributionWO,[],1)].^2,1))); +disp(' done.') + +% Extract the mean and error of the botstrapped disributions of mean errors +y_m = mean(y,2); +ywo_m = mean(woy,2); +y_e = [y_m, y_m] + 2*[-std(y,[],2),std(y,[],2)]; +ywo_e = [ywo_m, ywo_m] + 2*[-std(woy,[],2),std(woy,[],2)]; +se.s.lesioned_e = ywo_e; +se.s.lesioned_m = ywo_m; +se.s.unlesioned_e = y_e; +se.s.unlesioned_m = y_m; +se.s.lesioned.xbins = woxhis; +se.s.unlesioned.xbins = xhis; +se.s.min_x = min_x; +se.s.max_x = max_x; + +end diff --git a/compute/feFitModel.m b/compute/feFitModel.m new file mode 100755 index 0000000..db46f41 --- /dev/null +++ b/compute/feFitModel.m @@ -0,0 +1,100 @@ +function [fit, w, R2] = feFitModel(M,dSig,fitMethod) +% +% feFitModel() function in LiFE but restricted to the +% +% BBNNLS algorithm and using the Factorization model. +% M is the factorization model composed by: +% +% M.DictSig Dictionary +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + + +% Below are the old comments which are not longer correct in general +% Fit the LiFE model. +% +% Finds the weights for each fiber to best predict the directional +% diffusion signal (dSig) +% +% fit = feFitModel(M,dSig,fitMethod) +% +% dSig: The diffusion weighted signal measured at each +% voxel in each direction. These are extracted from +% the dwi data at some white-matter coordinates. +% M: The LiFE difusion model matrix, constructed +% by feConnectomeBuildModel.m +% +% fitMethod: +% - 'bbnnls' - DEFAULT and best, faster large-scale solver. +% +% See also: feCreate.m, feConnectomeBuildModel.m, feGet.m, feSet.m +% +% Example: +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com +% +% Notes about the LiFE model: +% +% The rows of the M matrix are nVoxels*nBvecs. We are going to predict the +% diffusion signal in each voxel for each direction. +% +% The columns of the M matrix are nFibers + nVoxels. The diffusion signal +% for each voxel is predicted as the weighted sum of predictions from each +% fibers that passes through a voxel plus an isotropic (CSF) term. +% +% In addition to M, we typically return dSig, which is the signal measured +% at each voxel in each direction. These are extracted from the dwi data +% and knowledge of the roiCoords. + +% fit the model, by selecting the proper toolbox. + +mycomputer = computer(); +release = version('-release'); + +switch fitMethod + case {'bbnnls'} + [nFibers] = size(M.Phi,3); %feGet(fe,'nfibers'); + %[nTheta] = size(M.DictSig,1); + [nAtoms] = size(M.DictSig,2); %feGet(fe,'natoms'); + [Nvoxels] = size(M.Phi,2); %feGet(fe,'nvoxels'); + + tic + fprintf('\nLiFE: Computing least-square minimization with BBNNLS...\n') + opt = solopt; + opt.maxit = 5000; + opt.use_tolo = 1; + + switch strcat(mycomputer,'_',release) + case {'GLNXA64_2015a'} + out_data = bbnnls_GLNXA64(M,dSig,zeros(nFibers,1),opt); + case {'MACI64_2014b'} + out_data = bbnnls_MACI64(M,dSig,zeros(nFibers,1),opt); + otherwise + sprintf('WARNING: currently LiFE is optimized for an efficient usage of memory \n using the Sparse Tucker Decomposition aproach (Caiafa&Pestilli, 2015) \n ONLY for Linux (MatlabR2015a) and MacOS (MatlabR2014b). \n If you have a different system or version you can still \n use the old version of LiFE (memory intensive). \n\n') + sprintf('\n Starting using old version of LiFE...\n') + out_data = bbnnls_OLD(M.MmatrixM,dSig,zeros(nFibers,1),opt); + end + fprintf('BBNNLS status: %s\nReason: %s\n',out_data.status,out_data.termReason); + w = out_data.x; + fprintf(' ...fit process completed in %2.3fminutes\n',toc/60) + % Save the state of the random generator so that the stochasit cfit can be recomputed. + defaultStream = RandStream.getGlobalStream; %RandStream.getDefaultStream; + fit.randState = defaultStream.State; + + % Save out some results + fit.results.R2 = []; + fit.results.nParams = size(M,2); + fit.results.nMeasures = size(M,1); + R2=[]; + + otherwise + error('Cannot fit LiFE model using method: %s.\n',fitMethod); +end + +% Save output structure. +fit.weights = w; +fit.params.fitMethod = fitMethod; + +end diff --git a/compute/feFitModel_OLD.m b/compute/feFitModel_OLD.m new file mode 100755 index 0000000..26c2212 --- /dev/null +++ b/compute/feFitModel_OLD.m @@ -0,0 +1,188 @@ +function [fit, w, R2] = feFitModel_OLD(M,dSig,fitMethod) +% +% feFitModel() function in LiFE but restricted to the +% +% BBNNLS algorithm and using the Factorization model. +% M is the factorization model composed by: +% +% M.DictSig Dictionary +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + + +% Below are the old comments which are not longer correct in general +% Fit the LiFE model. +% +% Finds the weights for each fiber to best predict the directional +% diffusion signal (dSig) +% +% fit = feFitModel(M,dSig,fitMethod) +% +% dSig: The diffusion weighted signal measured at each +% voxel in each direction. These are extracted from +% the dwi data at some white-matter coordinates. +% M: The LiFE difusion model matrix, constructed +% by feConnectomeBuildModel.m +% +% fitMethod: +% - 'bbnnls' - DEFAULT and best, faster large-scale solver. +% - 'lsqnonneg' - MatLab defaoult non-negative least-square solver (SLOW) +% - 'sgd', 'sgdnn' - Stochastic gradient descent. +% - 'sgdl1','sgdl1nn' - Stochastic gradient descent with L1 constrain on weights. +% +% See also: feCreate.m, feConnectomeBuildModel.m, feGet.m, feSet.m +% +% Example: +% +% Copyright (2013-2014), Franco Pestilli, Stanford University, pestillifranco@gmail.com. +% +% Notes about the LiFE model: +% +% The rows of the M matrix are nVoxels*nBvecs. We are going to predict the +% diffusion signal in each voxel for each direction. +% +% The columns of the M matrix are nFibers + nVoxels. The diffusion signal +% for each voxel is predicted as the weighted sum of predictions from each +% fibers that passes through a voxel plus an isotropic (CSF) term. +% +% In addition to M, we typically return dSig, which is the signal measured +% at each voxel in each direction. These are extracted from the dwi data +% and knowledge of the roiCoords. + +% fit the model, by selecting the proper toolbox. +switch fitMethod + case {'bbnnls'} + [nFibers] = size(M,2); %feGet(fe,'nfibers'); + %[nTheta] = size(M.DictSig,1); + %[nAtoms] = size(M.DictSig,2); %feGet(fe,'natoms'); + %[Nvoxels] = size(M.Phi,2); %feGet(fe,'nvoxels'); + + tic + fprintf('\nLiFE: Computing least-square minimization with BBNNLS...\n') + opt = solopt; + opt.maxit = 5000; + opt.use_tolo = 1; + out_data = bbnnls_OLD(M,dSig,zeros(nFibers,1),opt); + fprintf('BBNNLS status: %s\nReason: %s\n',out_data.status,out_data.termReason); + w = out_data.x; + fprintf(' ...fit process completed in %2.3fminutes\n',toc/60) + % Save the state of the random generator so that the stochasit cfit can be recomputed. + defaultStream = RandStream.getGlobalStream; %RandStream.getDefaultStream; + fit.randState = defaultStream.State; + + % Save out some results + fit.results.R2 = []; + fit.results.nParams = size(M,2); + fit.results.nMeasures = size(M,1); + R2=[]; +% case {'sgd','sgdnn'}% stochastic gradient descend, or non-negative stochastic gradient descend +% tic +% % Stochastic gradient descent method. +% % it solves an L2 minimization problem with non-negative constrain. +% % +% % Basically it takes 'chuncks' of rows of the M matrix and solves those +% % separately but contraining to obtain a consistent global solution. +% signalSiz = size(M,1); +% if signalSiz >= 1000000 +% siz = floor(signalSiz * .1); % size of the chuncks (number rows) taken at every iteration of the solver +% elseif signalSiz > 10000 || signalSiz < 1000000 +% siz = floor(signalSiz * .5); % size of the chunks (number rows) taken at every iteration of the solver +% elseif signalSiz <= 10000 +% siz = signalSiz; % size of the chuncks (number rows) taken at every iteration of the solver +% else +% keyboard +% end +% stepSiz = 0.0124; % step in the direction of the gradient, the larger the more prone to local minima +% stopCriteria = [.1 5 1]; % Stop signals: +% % First, if total error has not decreased less than +% % an XXX proportion of XXXX. +% % Second, number of small partial fits before +% % evaluating the quality of the large fit. +% % Third, Amount of R2 improvement judged to be +% % useful. +% % It used to be: percent improvement in R2 +% % that is considered a change in quality +% % of fit, e.g., 1=1%. +% n = 100; % Number of iteration after which to check for total error. +% nonneg = strcmpi(fitMethod(end-2:end),'dnn'); +% fprintf('\nLiFE: Computing least-square minimization with Stochastic Gradient Descent...\n') +% [w, R2] = sgd(dSig,M,siz, stepSiz, stopCriteria, n, nonneg); +% %sgd(y, X,numtoselect,finalstepsize,convergencecriterion,checkerror,nonneg,alpha,lambda) +% % Save out the Stochastic Gradient Descent parameters +% fit.params.stepSiz = stepSiz; +% fit.params.stopCriteria = stopCriteria; +% fit.params.numInters = n; +% +% % Save the state of the random generator so that the stochasit cfit can be recomputed. +% defaultStream = RandStream.getGlobalStream; %RandStream.getDefaultStream; +% fit.randState = defaultStream.State; +% +% % Save out some results +% fit.results.R2 = R2; +% fit.results.nParams = size(M,2); +% fit.results.nMeasures = size(M,1); +% fprintf(' ...fit process completed in %2.3fs\n',toc) +% +% case {'sgdl1','sgdl1nn'}% stochastic gradient descend, or non-negative stochastic gradient descend +% tic +% % Stochastic gradient descent method. +% % it solves an L2 minimization problem with non-negative constrain. +% % +% % Basically it takes 'chuncks' of rows of the M matrix and solves those +% % separately but contraining to obtain a consistent global solution. +% signalSiz = size(M,1); +% if signalSiz >= 1000000 +% siz = floor(signalSiz * .1); % size of the chunks (number rows) taken at every iteration of the solver +% elseif signalSiz > 10000 || signalSiz < 1000000 +% siz = floor(signalSiz * .5); % size of the chunks (number rows) taken at every iteration of the solver +% elseif signalSiz <= 10000 +% siz = signalSiz; % size of the chunks (number rows) taken at every iteration of the solver +% else +% keyboard +% end +% stepSiz = 0.0124; % step in the direction of the gradient, the larger the more prone to local minima +% stopCriteria = [.1 5 1]; % Stop signals: +% % First, if total error has not decreased less than +% % an XXX proportion of XXXX. +% % Second, number of small partial fits before +% % evaluating the quality of the large fit. +% % Third, Amount of R2 improvement judged to be +% % useful. +% % It used to be: percent improvement in R2 +% % that is considered a change in quality +% % of fit, e.g., 1=1%. +% n = 100; % Number of iteration after which to check for total error. +% nonneg = 1; +% fprintf('\nLiFE: Computing least-square minimization (L1) with Stochastic Gradient Descent...\n') +% %lambda = [length(dSig)*2.75]; +% [w, R2] = sgdL1(dSig,M,siz, stepSiz, stopCriteria, n,nonneg,[],lambda); +% fprintf('Lambda: %2.2f | nFibers: %i | L1 penalty: %2.3f | L2 penalty: %2.3f\n',lambda, length(find(w>0)),sum(w),sum(w.^2)) +% +% % Save out the Stochastic Gradient Descent parameters +% fit.params.stepSiz = stepSiz; +% fit.params.stopCriteria = stopCriteria; +% fit.params.numInters = n; +% +% % Save the state of the random generator so that the stochasit cfit can be recomputed. +% defaultStream = RandStream.getGlobalStream; %RandStream.getDefaultStream; +% fit.randState = defaultStream.State; +% +% % Save out some results +% fit.results.R2 = R2; +% fit.results.nParams = size(M,2); +% fit.results.nMeasures = size(M,1); +% fit.results.l2 = sum(w.^2); +% fit.results.l1 = sum(w); +% +% fprintf(' ...fit process completed in %2.3fs\n',toc) +% + otherwise + error('Cannot fit LiFE model using method: %s.\n',fitMethod); +end + +% Save output structure. +fit.weights = w; +fit.params.fitMethod = fitMethod; + +end diff --git a/compute/feGetConnectomeInfo.m b/compute/feGetConnectomeInfo.m new file mode 100755 index 0000000..92dffaf --- /dev/null +++ b/compute/feGetConnectomeInfo.m @@ -0,0 +1,50 @@ +function fe = feGetConnectomeInfo(fe) +% Find the unique fibers in a connectome. +% +% unique_fibers_index = feGetConnectomeInfo(fe) +% +% We identify the fibers that have identical trajectories (that pass +% through exactly the same voxels) within the ROI. These are stored in the +% fe slot 'unique index'. +% +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + +% Get the indexes to the voxels actually used to build LifE. +% Remember that voxels with no fibers are disregarded during the build. +usedVoxels = feGet(fe,'usedVoxels'); +nVoxels = length(usedVoxels); + +% preallocate memory for speed. +f = cell( nVoxels,1); % This will contain all the fibers in each voxel +unique_fibers_index= cell( nVoxels,1); % This will contain the *unique* fibers in each voxel +unique_fibers_num = zeros(nVoxels,1); % This will contain the number of unique fibers in each voxel + +% Get the fibers and unique fibers from voxel2FNpairs, in each voxel: +parfor vv = 1:nVoxels + % This is the index of the voxel used, it is used to address voxel2FNpair + voxIndex = usedVoxels(vv); + + % Indexes to the fibers in the current voxel + f{vv} = fe.life.voxel2FNpair{voxIndex}(:,1); + + % Reduce to the unique fibers: + unique_fibers_index{vv} = sort(unique(f{vv})); + unique_fibers_num(vv) = length(unique_fibers_index{vv}); +end + +tot_fibers_num = cellfun(@length,f); + +% Set them in the fe structure: +% Indexes to the unique fibers going through each voxel +fe = feSet(fe,'index to unique fibers in each voxel', unique_fibers_index); +% Number of unique fibers going through each voxel +fe = feSet(fe,'number of unique fibers in each voxel', unique_fibers_num); + +% Number of total fibers going trhough each voxel +fe = feSet(fe,'number of total fibers in each voxel', tot_fibers_num); +% Indexes to the total fibers going through each voxel +fe = feSet(fe,'index of total fibers in each voxel', f); + +return diff --git a/external/ByteSize.m b/external/ByteSize.m new file mode 100755 index 0000000..0c971fb --- /dev/null +++ b/external/ByteSize.m @@ -0,0 +1,36 @@ +function str = ByteSize(in, fid) +% BYTESIZE writes the memory usage of the provide variable to the given file +% identifier. Output is written to screen if fid is 1, empty or not provided. + +if nargin == 1 || isempty(fid) + fid = 1; +end + +s = whos('in'); +str = Bytes2str(s.bytes); +%fprintf(fid,[Bytes2str(s.bytes) '\n']); +end + +function str = Bytes2str(NumBytes) +% BYTES2STR Private function to take integer bytes and convert it to +% scale-appropriate size. + +scale = floor(log(NumBytes)/log(1024)); +switch scale + case 0 + str = [sprintf('%.0f',NumBytes) ' b']; + case 1 + str = [sprintf('%.2f',NumBytes/(1024)) ' kb']; + case 2 + str = [sprintf('%.2f',NumBytes/(1024^2)) ' Mb']; + case 3 + str = [sprintf('%.2f',NumBytes/(1024^3)) ' Gb']; + case 4 + str = [sprintf('%.2f',NumBytes/(1024^4)) ' Tb']; + case -inf + % Size occasionally returned as zero (eg some Java objects). + str = 'Not Available'; + otherwise + str = 'Over a petabyte!!!'; +end +end \ No newline at end of file diff --git a/external/M_times_w.m b/external/M_times_w.m new file mode 100755 index 0000000..0973623 --- /dev/null +++ b/external/M_times_w.m @@ -0,0 +1,24 @@ +function [y] = M_times_w(M,w) +% This function computes the matrix by vector product M*w +% using the factorized version of M which consists on only +% two components: +% 1) The Dictionary M.DictSig; +% 2) A sparse 3D array Phi with size [nAtoms,Nvoxels,nFibers] + +% The following makes w'*Phi_{(3)} (multiplication in mode-1) +y = ttv(M.Phi,w,3); % This is memory efficient version of above + +% The following makes ans \times_1 Dic +if nnz(y) + y = ttm(y,M.DictSig,1); +else + y = sptensor([size(M.DictSig,1),size(y,2)]); % In case empty tensor +end + +%y = sptenmat(y,1); % sptensor -> sptenmat +y = tenmat(y,1); % sptensor -> tenmat +y = double(y); % tenmat -> sparse matrix +y = y(:); % vectorize + +end + diff --git a/external/Mtransp_times_b_mex.mexmaci64 b/external/Mtransp_times_b_mex.mexmaci64 new file mode 100755 index 0000000000000000000000000000000000000000..803dab266714ea0a3a6a6aae60f92c726b528f54 GIT binary patch literal 51028 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 b^cLZ*T2zMc?7K%``f{))mGt|c8sq;18fie7 literal 0 HcmV?d00001 diff --git a/external/bbnnls_GLNXA64.m b/external/bbnnls_GLNXA64.m new file mode 100755 index 0000000..0d3b124 --- /dev/null +++ b/external/bbnnls_GLNXA64.m @@ -0,0 +1,281 @@ +%function out = bbnnls_New(A, b, x0, opt) +function out = bbnnls_GLNXA64(M, b, x0, opt) +% This is a modified version of BBNNLS code originally written by Suvrit Sra, Dongmin Kim +% This version accept as parameter a factorization of matrix A which is a +% structure M containing: +% 1) The Dictionary M.DictSig; +% 2) A sparse 3D array M.Phi with size [nFibers,nAtoms,Nvoxels] +% The modification was written by C. Caiafa (2015) + + + +% BBNNLS -- Solve NNLS problems via SBB +% +% WARNING Use at own risk! +% NOTE --- guaranteed convergence phase: *REMOVED* for speedup!! +% NOTE --- To speed up code further, *REMOVE* debugging part +% +% +% function out = bbnnls(A, b, x0, ) +% Solve a bound-constrained least squares problem, +% min 0.5*||Ax-b||^2, s.t. x >= 0 +% +% +% x0 -- Starting vector (useful for warm-starts). +% +% OPT -- This structure contains important opt that control how the +% optimization procedure runs. To obtain a default structure the user can +% use 'opt = solopt'. Use 'help solopt' to get a description of +% what the individual opt mean. +% +% Most important options to tune as: opt.tolg, opt.maxit +% +% +% OUT contains the solution and other information about the optimization or +% info indicating whether the method succeeded or failed. +% +% See also: solopt, bcls +% +% Version 1.1 (c) 2010 Suvrit Sra, Dongmin Kim +% +% Released under the GNU General Public License +% For details on license and terms please see http://www.gnu.org/copyleft/gpl.html +% +% This version was updated from the orignal +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + + + %fgx = @(x) funcGrad(A,b, x); % function to compute obj and grad + + fgx = @(x) funcGrad(M, b, x); % function to compute obj and grad + + % do some initialization for maintaining statistics + out.iter = 0; + out.iterTimes = nan*ones(opt.maxit,1); + out.objTimes = nan*ones(opt.maxit,1); + out.pgTimes = nan*ones(opt.maxit,1); + out.trueError = nan*ones(opt.maxit,1); + out.startTime = tic; + out.status = 'Failure'; + + % HINT: Very important for overall speed is to have a good x0 + out.x = x0; + out.refx = x0; + [out.refobj, out.grad] = fgx(out.x); + out.oldg = out.grad; + out.refg = out.oldg; + + + %% Begin the main algorithm + if (opt.verbose) + fprintf('Running: **** SBB-NNLS ****\n\n'); + fprintf('Iter \t Obj\t\t ||pg||_inf\t\t ||x-x*||\n'); + fprintf('-------------------------------------------------------\n'); + end + + objectives = zeros(opt.maxit,1); + %f = figure; + while 1 + out.iter = out.iter + 1; + + % HINT: edit checkTermination to determine good criterion for yourself! + [termReason, out.pgTimes(out.iter)] = checkTermination(opt, out); + if (termReason > 0), break; end + + % HINT: computeBBStep is the one to implement most carefully + %[step out] = computeBBStep(A, b, out); + [step out] = computeBBStep(M, b, out); + out.x = out.x - step * out.grad; + out.oldg = out.grad; + + % HINT: projection step: can replace the 0 by an epsilon to truncate + % values close to 0 + out.x(out.x < 0) = 0; + + [out.obj out.grad] = fgx(out.x); + + objectives(out.iter) = out.obj; +% clf; +% plot(objectives); +% title('Objective ||Ax-b||^2'); +% xlabel('Iteration'); +% ylabel('Objective'); +% drawnow; + + % HINT: can remove, as this is just for statistics + out.objTimes (out.iter) = out.obj; + out.iterTimes(out.iter) = toc(out.startTime); + + % HINT: for debugging, to see how result develops if true x* is known + if (opt.truex), out.trueError(out.iter) = norm(opt.xt-out.x); end + if (opt.verbose) + fprintf('%04d\t %E\t%E\t%E\n', out.iter, out.obj, out.pgTimes(out.iter), out.trueError(out.iter)); + end + end % of while + + %% Final statistics and wrap up + out.time = toc(out.startTime); + out.status = 'Success'; + out.termReason = setTermReason(termReason); +end + +% Compute BB step; for SBB also modifies out.oldg, and this change must be +% passed back to the calling routine, else it will fail! +%function [step out] = computeBBStep(A, b, out) +function [step out] = computeBBStep(A, b, out) + [nTheta] = size(A.DictSig,1); + [nAtoms] = size(A.Phi,1); + [nFibers] = size(A.Phi,3); %feGet(fe,'nfibers'); + [nVoxels] = size(A.Phi,2); %feGet(fe,'nvoxels'); + + % HINT: Can tune the x==0 to replace it by an epsilon to do TUNING + gp = find(out.x == 0 & out.grad > 0); + out.oldg(gp) = 0; + + %Ag = A*out.oldg; % A*oldg + Ag = M_times_w(A,out.oldg); % A*oldg + %Ag = M_times_w_LOOP_mex(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,out.oldg,nTheta,nVoxels); + %Agn = M_times_w_par(A,out.oldg); % A*oldg + + + % HINT: In my experience, the falling alternating steps perform better + if (mod(out.iter, 2) == 0) + step = (out.oldg' * out.oldg) / (Ag' * Ag); + else + numer = Ag' * Ag; + + %Ag0 = Ag; +% Ag = A'*Ag; + %Ag = Mtransp_times_b_NOloop(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels])); + %Ag = Mtransp_times_b_mex(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels]),nFibers); % MEX default compiler version + Ag = Mtransp_times_b_mex_v2015a_Intel(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels]),nFibers); % MEX Intel compiler version + %Ag = Mtransp_times_b_mex_oIcc_oMan(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels]),nFibers); + + % Agn = Mtransp_times_b_new(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag0,[nTheta,nVoxels])); +% Ag = Mtransp_times_b_par(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels]),nFibers); +% Ag = Mtransp_times_b(A,Ag); + + Ag(gp) = 0; + step = numer / (Ag' * Ag); + end +end + +% compute obj function and gradient --- requires good implementation of A*x +% and A'*y for appropriate x and y +function [f g] = funcGrad(A, b, x) + [nFibers] = size(A.Phi,3); %feGet(fe,'nfibers'); + [nTheta] = size(A.DictSig,1); + [nAtoms] = size(A.DictSig,2); %feGet(fe,'natoms'); + [nVoxels] = size(A.Phi,2); %feGet(fe,'nvoxels'); + + %Ax = A*x - b; + Ax = M_times_w(A,x) - b; + %Ax = M_times_w_LOOP_mex(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,x,nTheta,nVoxels) - b; + + f = 0.5*norm(Ax)^2; + if (nargout > 1) +% g = A'*Ax; +% g = +% Mtransp_times_b_mex(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ax,[nTheta,nVoxels]),nFibers); +% % MEX default compiler version + g = Mtransp_times_b_mex_v2015a_Intel(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ax,[nTheta,nVoxels]),nFibers);% MEX Intel compiler version + %g = Mtransp_times_b_mex_oIcc_oMan(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ax,[nTheta,nVoxels]),nFibers); + + %g = Mtransp_times_b_NOloop(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ax,[nTheta,nVoxels])); +% g = Mtransp_times_b(A,Ax); + end +end + +% check various termination criteria; return norm of pg +% the strictest is norm of pg +% HINT: for speedup, use maybe just opt.tolo or some other criterion that +% you like. +function [v pg] = checkTermination(options, out) + % pgnorm limit -- need to check this first of all + gp = find( (out.x ~= 0 | out.grad < 0)); + + pg = norm(out.grad(gp), 'inf'); + if (pg < options.tolg), v=8; return; end + + % First check if we are doing termination based on running time + if (options.time_limit) + out.time = etime(clock, out.start_time); + if (out.time >= options.maxtime) + v = 1; + return; + end + end + + % Now check if we are doing break by tolx + if (options.use_tolx) + if (norm(out.x-out.oldx)/norm(out.oldx) < options.tolx) + v = 2; + return; + end + end + + % Are we doing break by tolo (tol obj val) + if (options.use_tolo && out.iter > 2) + delta = abs(out.objTimes(out.iter-1)-out.objTimes(out.iter-2)); + if (delta < options.tolo) + v = 3; + return; + end + end + + % Finally the plain old check if max iter has been achieved + if (out.iter >= options.maxit) + v = 4; + return; + end + + % KKT violation + if (options.use_kkt) + if abs(out.x' * out.grad) <= options.tolk + v = 7; + return; + end + end + + + % All is ok... + v = 0; +end + +%% Prints status +function showStatus(out, options) + if (options.verbose) + fprintf('.'); + if (mod(out.iter, 30) == 0) + fprintf('\n'); + end + end +end + +% String representation of termination +function r = setTermReason(t) + switch t + case 1 + r = 'Exceeded time limit'; + case 2 + r = 'Relative change in x small enough'; + case 3 + r = 'Relative change in objvalue small enough'; + case 4 + r = 'Maximum number of iterations reached'; + case 5 + r = '|x_t+1 - x_t|=0 or |grad_t+1 - grad_t| < 1e-9'; + case 6 + r = 'Line search failed'; + case 7 + r = '|x^T * grad| < opt.pbb_gradient_norm'; + case 8 + r = '|| grad ||_inf < opt.tolg'; + case 100 + r = 'The active set converged'; + otherwise + r = 'Undefined'; + end +end + diff --git a/external/bbnnls_MACI64.m b/external/bbnnls_MACI64.m new file mode 100755 index 0000000..52e26dd --- /dev/null +++ b/external/bbnnls_MACI64.m @@ -0,0 +1,278 @@ +%function out = bbnnls_New(A, b, x0, opt) +function out = bbnnls_MACI64(M, b, x0, opt) +% This is a modified version of BBNNLS code originally written by Suvrit Sra, Dongmin Kim +% This version accept as parameter a factorization of matrix A which is a +% structure M containing: +% 1) The Dictionary M.DictSig; +% 2) A sparse 3D array M.Phi with size [nFibers,nAtoms,Nvoxels] +% The modification was written by C. Caiafa (2015) + + + +% BBNNLS -- Solve NNLS problems via SBB +% +% WARNING Use at own risk! +% NOTE --- guaranteed convergence phase: *REMOVED* for speedup!! +% NOTE --- To speed up code further, *REMOVE* debugging part +% +% +% function out = bbnnls(A, b, x0, ) +% Solve a bound-constrained least squares problem, +% min 0.5*||Ax-b||^2, s.t. x >= 0 +% +% +% x0 -- Starting vector (useful for warm-starts). +% +% OPT -- This structure contains important opt that control how the +% optimization procedure runs. To obtain a default structure the user can +% use 'opt = solopt'. Use 'help solopt' to get a description of +% what the individual opt mean. +% +% Most important options to tune as: opt.tolg, opt.maxit +% +% +% OUT contains the solution and other information about the optimization or +% info indicating whether the method succeeded or failed. +% +% See also: solopt, bcls +% +% Version 1.1 (c) 2010 Suvrit Sra, Dongmin Kim +% +% Released under the GNU General Public License +% For details on license and terms please see http://www.gnu.org/copyleft/gpl.html +% +% This version was updated from the orignal +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + + + %fgx = @(x) funcGrad(A,b, x); % function to compute obj and grad + + fgx = @(x) funcGrad(M, b, x); % function to compute obj and grad + + % do some initialization for maintaining statistics + out.iter = 0; + out.iterTimes = nan*ones(opt.maxit,1); + out.objTimes = nan*ones(opt.maxit,1); + out.pgTimes = nan*ones(opt.maxit,1); + out.trueError = nan*ones(opt.maxit,1); + out.startTime = tic; + out.status = 'Failure'; + + % HINT: Very important for overall speed is to have a good x0 + out.x = x0; + out.refx = x0; + [out.refobj, out.grad] = fgx(out.x); + out.oldg = out.grad; + out.refg = out.oldg; + + + %% Begin the main algorithm + if (opt.verbose) + fprintf('Running: **** SBB-NNLS ****\n\n'); + fprintf('Iter \t Obj\t\t ||pg||_inf\t\t ||x-x*||\n'); + fprintf('-------------------------------------------------------\n'); + end + + objectives = zeros(opt.maxit,1); + %f = figure; + while 1 + out.iter = out.iter + 1; + + % HINT: edit checkTermination to determine good criterion for yourself! + [termReason, out.pgTimes(out.iter)] = checkTermination(opt, out); + if (termReason > 0), break; end + + % HINT: computeBBStep is the one to implement most carefully + %[step out] = computeBBStep(A, b, out); + [step out] = computeBBStep(M, b, out); + out.x = out.x - step * out.grad; + out.oldg = out.grad; + + % HINT: projection step: can replace the 0 by an epsilon to truncate + % values close to 0 + out.x(out.x < 0) = 0; + + [out.obj out.grad] = fgx(out.x); + + objectives(out.iter) = out.obj; +% clf; +% plot(objectives); +% title('Objective ||Ax-b||^2'); +% xlabel('Iteration'); +% ylabel('Objective'); +% drawnow; + + % HINT: can remove, as this is just for statistics + out.objTimes (out.iter) = out.obj; + out.iterTimes(out.iter) = toc(out.startTime); + + % HINT: for debugging, to see how result develops if true x* is known + if (opt.truex), out.trueError(out.iter) = norm(opt.xt-out.x); end + if (opt.verbose) + fprintf('%04d\t %E\t%E\t%E\n', out.iter, out.obj, out.pgTimes(out.iter), out.trueError(out.iter)); + end + end % of while + + %% Final statistics and wrap up + out.time = toc(out.startTime); + out.status = 'Success'; + out.termReason = setTermReason(termReason); +end + +% Compute BB step; for SBB also modifies out.oldg, and this change must be +% passed back to the calling routine, else it will fail! +%function [step out] = computeBBStep(A, b, out) +function [step out] = computeBBStep(A, b, out) + [nTheta] = size(A.DictSig,1); + [nAtoms] = size(A.Phi,1); + [nFibers] = size(A.Phi,3); %feGet(fe,'nfibers'); + [nVoxels] = size(A.Phi,2); %feGet(fe,'nvoxels'); + + % HINT: Can tune the x==0 to replace it by an epsilon to do TUNING + gp = find(out.x == 0 & out.grad > 0); + out.oldg(gp) = 0; + + %Ag = A*out.oldg; % A*oldg + Ag = M_times_w(A,out.oldg); % A*oldg + %Ag = M_times_w_LOOP_mex(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,out.oldg,nTheta,nVoxels); + %Agn = M_times_w_par(A,out.oldg); % A*oldg + + + % HINT: In my experience, the falling alternating steps perform better + if (mod(out.iter, 2) == 0) + step = (out.oldg' * out.oldg) / (Ag' * Ag); + else + numer = Ag' * Ag; + + %Ag0 = Ag; +% Ag = A'*Ag; + %Ag = Mtransp_times_b_NOloop(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels])); + Ag = Mtransp_times_b_mex(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels]),nFibers); % MEX default compiler version + %Ag = Mtransp_times_b_mex_v2015a_Intel(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels]),nFibers); % MEX Intel compiler version + %Ag = Mtransp_times_b_mex_oIcc_oMan(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels]),nFibers); + + % Agn = Mtransp_times_b_new(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag0,[nTheta,nVoxels])); +% Ag = Mtransp_times_b_par(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ag,[nTheta,nVoxels]),nFibers); +% Ag = Mtransp_times_b(A,Ag); + + Ag(gp) = 0; + step = numer / (Ag' * Ag); + end +end + +% compute obj function and gradient --- requires good implementation of A*x +% and A'*y for appropriate x and y +function [f g] = funcGrad(A, b, x) + [nFibers] = size(A.Phi,3); %feGet(fe,'nfibers'); + [nTheta] = size(A.DictSig,1); + [nAtoms] = size(A.DictSig,2); %feGet(fe,'natoms'); + [nVoxels] = size(A.Phi,2); %feGet(fe,'nvoxels'); + + %Ax = A*x - b; + Ax = M_times_w(A,x) - b; + %Ax = M_times_w_LOOP_mex(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,x,nTheta,nVoxels) - b; + + f = 0.5*norm(Ax)^2; + if (nargout > 1) +% g = A'*Ax; + g = Mtransp_times_b_mex(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ax,[nTheta,nVoxels]),nFibers); % MEX default compiler version + %g = Mtransp_times_b_mex_v2015a_Intel(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ax,[nTheta,nVoxels]),nFibers);% MEX Intel compiler version + %g = Mtransp_times_b_mex_oIcc_oMan(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ax,[nTheta,nVoxels]),nFibers); + %g = Mtransp_times_b_NOloop(A.Phi.subs(:,1),A.Phi.subs(:,2),A.Phi.subs(:,3),A.Phi.vals,A.DictSig,reshape(Ax,[nTheta,nVoxels])); +% g = Mtransp_times_b(A,Ax); + end +end + +% check various termination criteria; return norm of pg +% the strictest is norm of pg +% HINT: for speedup, use maybe just opt.tolo or some other criterion that +% you like. +function [v pg] = checkTermination(options, out) + % pgnorm limit -- need to check this first of all + gp = find( (out.x ~= 0 | out.grad < 0)); + + pg = norm(out.grad(gp), 'inf'); + if (pg < options.tolg), v=8; return; end + + % First check if we are doing termination based on running time + if (options.time_limit) + out.time = etime(clock, out.start_time); + if (out.time >= options.maxtime) + v = 1; + return; + end + end + + % Now check if we are doing break by tolx + if (options.use_tolx) + if (norm(out.x-out.oldx)/norm(out.oldx) < options.tolx) + v = 2; + return; + end + end + + % Are we doing break by tolo (tol obj val) + if (options.use_tolo && out.iter > 2) + delta = abs(out.objTimes(out.iter-1)-out.objTimes(out.iter-2)); + if (delta < options.tolo) + v = 3; + return; + end + end + + % Finally the plain old check if max iter has been achieved + if (out.iter >= options.maxit) + v = 4; + return; + end + + % KKT violation + if (options.use_kkt) + if abs(out.x' * out.grad) <= options.tolk + v = 7; + return; + end + end + + + % All is ok... + v = 0; +end + +%% Prints status +function showStatus(out, options) + if (options.verbose) + fprintf('.'); + if (mod(out.iter, 30) == 0) + fprintf('\n'); + end + end +end + +% String representation of termination +function r = setTermReason(t) + switch t + case 1 + r = 'Exceeded time limit'; + case 2 + r = 'Relative change in x small enough'; + case 3 + r = 'Relative change in objvalue small enough'; + case 4 + r = 'Maximum number of iterations reached'; + case 5 + r = '|x_t+1 - x_t|=0 or |grad_t+1 - grad_t| < 1e-9'; + case 6 + r = 'Line search failed'; + case 7 + r = '|x^T * grad| < opt.pbb_gradient_norm'; + case 8 + r = '|| grad ||_inf < opt.tolg'; + case 100 + r = 'The active set converged'; + otherwise + r = 'Undefined'; + end +end + diff --git a/external/bbnnls_OLD.m b/external/bbnnls_OLD.m new file mode 100755 index 0000000..e5ac34a --- /dev/null +++ b/external/bbnnls_OLD.m @@ -0,0 +1,228 @@ +function out = bbnnls_OLD(A, b, x0, opt) +% BBNNLS -- Solve NNLS problems via SBB +% +% WARNING Use at own risk! +% NOTE --- guaranteed convergence phase: *REMOVED* for speedup!! +% NOTE --- To speed up code further, *REMOVE* debugging part +% +% +% function out = bbnnls(A, b, x0, opt) +% Solve a bound-constrained least squares problem, +% min 0.5*||Ax-b||^2, s.t. x >= 0 +% +% +% x0 -- Starting vector (useful for warm-starts). +% +% OPT -- This structure contains important opt that control how the +% optimization procedure runs. To obtain a default structure the user can +% use 'opt = solopt'. Use 'help solopt' to get a description of +% what the individual opt mean. +% +% Most important options to tune as: opt.tolg, opt.maxit +% +% +% OUT contains the solution and other information about the optimization or +% info indicating whether the method succeeded or failed. +% +% See also: solopt, bcls +% +% Version 1.1 (c) 2010 Suvrit Sra, Dongmin Kim +% +% Released under the GNU General Public License +% For details on license and terms please see http://www.gnu.org/copyleft/gpl.html + + + fgx = @(x) funcGrad(A,b, x); % function to compute obj and grad + + % do some initialization for maintaining statistics + out.iter = 0; + out.iterTimes = nan*ones(opt.maxit,1); + out.objTimes = nan*ones(opt.maxit,1); + out.pgTimes = nan*ones(opt.maxit,1); + out.trueError = nan*ones(opt.maxit,1); + out.startTime = tic; + out.status = 'Failure'; + + % HINT: Very important for overall speed is to have a good x0 + out.x = x0; + out.refx = x0; + [out.refobj, out.grad] = fgx(out.x); + out.oldg = out.grad; + out.refg = out.oldg; + + + %% Begin the main algorithm + if (opt.verbose) + fprintf('Running: **** SBB-NNLS ****\n\n'); + fprintf('Iter \t Obj\t\t ||pg||_inf\t\t ||x-x*||\n'); + fprintf('-------------------------------------------------------\n'); + end + + objectives = zeros(opt.maxit,1); + %f = figure; + while 1 + out.iter = out.iter + 1; + + % HINT: edit checkTermination to determine good criterion for yourself! + [termReason, out.pgTimes(out.iter)] = checkTermination(opt, out); + if (termReason > 0), break; end + + % HINT: computeBBStep is the one to implement most carefully + [step out] = computeBBStep(A, b, out); + out.x = out.x - step * out.grad; + out.oldg = out.grad; + + % HINT: projection step: can replace the 0 by an epsilon to truncate + % values close to 0 + out.x(out.x < 0) = 0; + + [out.obj out.grad] = fgx(out.x); + + objectives(out.iter) = out.obj; +% clf; +% plot(objectives); +% title('Objective ||Ax-b||^2'); +% xlabel('Iteration'); +% ylabel('Objective'); +% drawnow; + + % HINT: can remove, as this is just for statistics + out.objTimes (out.iter) = out.obj; + out.iterTimes(out.iter) = toc(out.startTime); + + % HINT: for debugging, to see how result develops if true x* is known + if (opt.truex), out.trueError(out.iter) = norm(opt.xt-out.x); end + if (opt.verbose) + fprintf('%04d\t %E\t%E\t%E\n', out.iter, out.obj, out.pgTimes(out.iter), out.trueError(out.iter)); + end + end % of while + + %% Final statistics and wrap up + out.time = toc(out.startTime); + out.status = 'Success'; + out.termReason = setTermReason(termReason); +end + +% Compute BB step; for SBB also modifies out.oldg, and this change must be +% passed back to the calling routine, else it will fail! +function [step out] = computeBBStep(A, b, out) + + % HINT: Can tune the x==0 to replace it by an epsilon to do TUNING + gp = find(out.x == 0 & out.grad > 0); + out.oldg(gp) = 0; + + Ag = A*out.oldg; % A*oldg + + % HINT: In my experience, the falling alternating steps perform better + if (mod(out.iter, 2) == 0) + step = (out.oldg' * out.oldg) / (Ag' * Ag); + else + numer = Ag' * Ag; + Ag = A'*Ag; % + Ag(gp) = 0; + step = numer / (Ag' * Ag); + end +end + +% compute obj function and gradient --- requires good implementation of A*x +% and A'*y for appropriate x and y +function [f g] = funcGrad(A, b, x) + Ax = A*x - b; + f = 0.5*norm(Ax)^2; + if (nargout > 1) + g = A'*Ax; + end +end + +% check various termination criteria; return norm of pg +% the strictest is norm of pg +% HINT: for speedup, use maybe just opt.tolo or some other criterion that +% you like. +function [v pg] = checkTermination(options, out) + % pgnorm limit -- need to check this first of all + gp = find( (out.x ~= 0 | out.grad < 0)); + + pg = norm(out.grad(gp), 'inf'); + if (pg < options.tolg), v=8; return; end + + % First check if we are doing termination based on running time + if (options.time_limit) + out.time = etime(clock, out.start_time); + if (out.time >= options.maxtime) + v = 1; + return; + end + end + + % Now check if we are doing break by tolx + if (options.use_tolx) + if (norm(out.x-out.oldx)/norm(out.oldx) < options.tolx) + v = 2; + return; + end + end + + % Are we doing break by tolo (tol obj val) + if (options.use_tolo && out.iter > 2) + delta = abs(out.objTimes(out.iter-1)-out.objTimes(out.iter-2)); + if (delta < options.tolo) + v = 3; + return; + end + end + + % Finally the plain old check if max iter has been achieved + if (out.iter >= options.maxit) + v = 4; + return; + end + + % KKT violation + if (options.use_kkt) + if abs(out.x' * out.grad) <= options.tolk + v = 7; + return; + end + end + + + % All is ok... + v = 0; +end + +%% Prints status +function showStatus(out, options) + if (options.verbose) + fprintf('.'); + if (mod(out.iter, 30) == 0) + fprintf('\n'); + end + end +end + +% String representation of termination +function r = setTermReason(t) + switch t + case 1 + r = 'Exceeded time limit'; + case 2 + r = 'Relative change in x small enough'; + case 3 + r = 'Relative change in objvalue small enough'; + case 4 + r = 'Maximum number of iterations reached'; + case 5 + r = '|x_t+1 - x_t|=0 or |grad_t+1 - grad_t| < 1e-9'; + case 6 + r = 'Line search failed'; + case 7 + r = '|x^T * grad| < opt.pbb_gradient_norm'; + case 8 + r = '|| grad ||_inf < opt.tolg'; + case 100 + r = 'The active set converged'; + otherwise + r = 'Undefined'; + end +end + diff --git a/external/emd-2005-02/Readme.txt b/external/emd-2005-02/Readme.txt new file mode 100755 index 0000000..0250ca6 --- /dev/null +++ b/external/emd-2005-02/Readme.txt @@ -0,0 +1,30 @@ + +EARTH MOVER'S DISTANCE +---------------------------------------- + + +VERSION/INFO +------------ + +This implementation is based on "The Earth Mover's Distance +as a Metric for Image Retrieval", Y. Rubner, C. Tomasi and L. Guibas, +International Journal of Computer Vision, 40(2), pp. 99-121, 2000. + + +USAGE +----- + +emd ---> computes the earth mover's distance between two signatures +gmd ---> computes the ground distance matrix between two signatures +gdf ---> computes the ground distance between two feature vectors +test --> is an auxiliary module to show how the above functions work + +COPYRIGHT +--------- + +These files and their content belong to Ulas Yilmaz. +You are welcome to use it for non-commercial purposes, such as +student projects, research and personal interest. However, +you are not allowed to use it for commercial purposes, without +an explicit written and signed license agreement with Ulas Yilmaz. +Berlin University of Technology, Germany 2005 \ No newline at end of file diff --git a/external/emd-2005-02/emd.m b/external/emd-2005-02/emd.m new file mode 100755 index 0000000..bee0b44 --- /dev/null +++ b/external/emd-2005-02/emd.m @@ -0,0 +1,69 @@ +function [x, fval] = emd(F1, F2, W1, W2, Func) +% EMD Earth Mover's Distance between two signatures. +% +% [X, FVAL] = EMD(F1, F2, W1, W2, FUNC) is the Earth Mover's Distance +% between two signatures S1 = {F1, W1} and S2 = {F2, W2}. F1 and F2 +% consists of feature vectors which describe S1 and S2, respectively. +% Weights of these features are stored in W1 and W2. FUNC is a function +% which computes the ground distance between two feature vectors. +% +% Example: +% ------- +% f1 = [[100, 40, 22]; [211, 20, 2]; [32, 190, 150]; [2, 100, 100]]; +% f2 = [[0, 0, 0]; [50, 100, 80]; [255, 255, 255]]; +% w1 = [0.4; 0.3; 0.2; 0.1]; +% w2 = [0.5; 0.3; 0.2]; +% ... +% [x fval] = emd(f1, f2, w1, w2, @gdf); +% ... +% +% EMD is formalized as linear programming problem in which the flow that +% minimizes an overall cost function subject to a set of constraints is +% computed. This implementation is based on "The Earth Mover's Distance +% as a Metric for Image Retrieval", Y. Rubner, C. Tomasi and L. Guibas, +% International Journal of Computer Vision, 40(2), pp. 99-121, 2000. +% +% The outcome of EMD is the flow (X) which minimizes the cost function +% and the value (FVAL) of this flow. +% +% This file and its content belong to Ulas Yilmaz. +% You are welcome to use it for non-commercial purposes, such as +% student projects, research and personal interest. However, +% you are not allowed to use it for commercial purposes, without +% an explicit written and signed license agreement with Ulas Yilmaz. +% Berlin University of Technology, Germany 2006. +% http://www.cv.tu-berlin.de/~ulas/RaRF +% + +% ground distance matrix +f = gdm(F1, F2, Func); + +% number of feature vectors +[m, ~] = size(F1); +[n, ~] = size(F2); + +% inequality constraints +A1 = zeros(m, m * n); +A2 = zeros(n, m * n); +for i = 1:m + for j = 1:n + k = j + (i - 1) * n; + A1(i, k) = 1; + A2(j, k) = 1; + end +end +A = [A1; A2]; +b = [W1; W2]; + +% equality constraints +Aeq = ones(m + n, m * n); +beq = ones(m + n, 1) * min(sum(W1), sum(W2)); + +% lower bound +lb = zeros(1, m * n); + +% linear programming +[x, fval] = linprog(f, sparse(A), b, sparse(Aeq), beq, lb); +fval = fval / sum(x); + +end diff --git a/external/emd-2005-02/gdf.m b/external/emd-2005-02/gdf.m new file mode 100755 index 0000000..693fd08 --- /dev/null +++ b/external/emd-2005-02/gdf.m @@ -0,0 +1,25 @@ +function [E] = gdf(V1, V2) +% GDF Ground distance between two vectors. +% +% [E] = GDF(F1, F2) is the ground distance between two feature vectors. +% +% Example: +% ------- +% v1 = [100, 40, 22]; +% v2 = [50, 100, 80]; +% ... +% [e] = gdf(v1, v2); +% ... +% +% This file and its content belong to Ulas Yilmaz. +% You are welcome to use it for non-commercial purposes, such as +% student projects, research and personal interest. However, +% you are not allowed to use it for commercial purposes, without +% an explicit written and signed license agreement with Ulas Yilmaz. +% Berlin University of Technology, Germany 2006. +% http://www.cv.tu-berlin.de/~ulas/RaRF +% + +E = norm(V1 - V2, 2); + +end diff --git a/external/emd-2005-02/gdm.m b/external/emd-2005-02/gdm.m new file mode 100755 index 0000000..7ec3c61 --- /dev/null +++ b/external/emd-2005-02/gdm.m @@ -0,0 +1,41 @@ +function [f] = gdm(F1, F2, Func) +% GDM Ground distance matrix between two signatures. +% +% [F] = GDM(F1, F2, FUNC) is the ground distance matrix between +% two signatures whose feature vectors are given in F1 and F2. +% FUNC is a function which computes the ground distance between +% two feature vectors. +% +% Example: +% ------- +% f1 = [[100, 40, 22]; [211, 20, 2]; [32, 190, 150]; [2, 100, 100]]; +% f2 = [[0, 0, 0]; [50, 100, 80]; [255, 255, 255]]; +% ... +% [f] = gdm(f1, f2, @gmf); +% ... +% +% This file and its content belong to Ulas Yilmaz. +% You are welcome to use it for non-commercial purposes, such as +% student projects, research and personal interest. However, +% you are not allowed to use it for commercial purposes, without +% an explicit written and signed license agreement with Ulas Yilmaz. +% Berlin University of Technology, Germany 2006. +% http://www.cv.tu-berlin.de/~ulas/RaRF +% + +% number and length of feature vectors +[m a] = size(F1); +[n a] = size(F2); + +% ground distance matrix +for i = 1:m + for j = 1:n + f(i, j) = Func(F1(i, 1:a), F2(j, 1:a)); + end +end + +% gdm in column-vector form +f = f'; +f = f(:); + +end diff --git a/external/emd-2005-02/test.m b/external/emd-2005-02/test.m new file mode 100755 index 0000000..31479a2 --- /dev/null +++ b/external/emd-2005-02/test.m @@ -0,0 +1,43 @@ +function [f, fval] = test(varargin) +% Test function for MatLab EMD. +% +% + +% Images +if nargin == 0 + A = imread('pout.tif'); + B = imread('cameraman.tif'); +elseif nargin == 2 + A = varargin{1}; + B = varargin{2}; + if ischar(A) + A = imread(A); + end; + if ischar(B) + B = imread(B); + end; +end; + +% Histograms +nbins = 10; +[ca ha] = imhist(A, nbins); +[cb hb] = imhist(B, nbins); + +% Features +f1 = ha; +f2 = hb; + +% Weights +w1 = ca / sum(ca); +w2 = cb / sum(cb); + +% Earth Mover's Distance +[f, fval] = emd(f1, f2, w1, w2, @gdf); + +% Results +wtext = sprintf('fval = %f', fval); +figure('Name', wtext); +subplot(121);imshow(A);title('first image'); +subplot(122);imshow(B);title('second image'); + +end diff --git a/external/solopt.m b/external/solopt.m new file mode 100755 index 0000000..c66181a --- /dev/null +++ b/external/solopt.m @@ -0,0 +1,39 @@ +function options = solopt(varargin) +% SOLOPT -- Creates a default options structure for BBNNLS +% +% OPTIONS = SOLOPT +% + +options.asgui = 0; +options.beta = 0.0498; +options.compute_obj = 1; +% diminishing scalar; beta^0 = opt.dimbeg +% beta^k = opt.dimbeg / k^opt.dimexp +options.dimexp = .5; +options.dimbeg = 5; +options.maxit = 100; +options.maxtime = 10; +options.maxnull = 10; +options.max_func_evals = 30; +options.pbb_gradient_norm = 1e-9; +options.sigma = 0.298; +options.step = 1e-4; +options.tau = 1e-7; +options.time_limit = 0; +options.tolg = 1e-3; +options.tolx = 1e-8; +options.tolo = 1e-5; +options.truex=0; +options.xt=[]; +options.use_kkt = 0; +options.use_tolg = 1; +options.use_tolo = 0; +options.use_tolx = 0; +options.useTwo = 0; +options.verbose = 1; % initially +if nargin == 1 + options.variant = varargin{1}; +else % Default + options.variant = 'SBB'; +end + diff --git a/external/tensor_toolbox_2.5/@ktensor/Contents.m b/external/tensor_toolbox_2.5/@ktensor/Contents.m new file mode 100755 index 0000000..161820a --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/Contents.m @@ -0,0 +1,36 @@ +% @KTENSOR +% +% Files +% arrange - Arranges the rank-1 components of a ktensor. +% datadisp - Special display of a ktensor. +% disp - Command window display for a ktensor. +% display - Command window display for a ktensor. +% double - Convert a ktensor to a double array. +% end - Last index of indexing expression for ktensor. +% extract - Creates a new ktensor with only the specified components. +% fixsigns - Fix sign ambiguity of a ktensor. +% full - Convert a ktensor to a (dense) tensor. +% innerprod - Efficient inner product with a ktensor. +% isequal - True if each component of two ktensor's is numerically equal. +% ktensor - Tensor stored as a Kruskal operator (decomposed). +% minus - Binary subtraction for ktensor. +% mtimes - Implement A*B (scalar multiply) for ktensor. +% mttkrp - Matricized tensor times Khatri-Rao product for ktensor. +% ncomponents - Number of components for a ktensor. +% ndims - Number of dimensions for a ktensor. +% norm - Frobenius norm of a ktensor. +% normalize - Normalizes the columns of the factor matrices. +% nvecs - Compute the leading mode-n vectors for a ktensor. +% permute - Permute dimensions of a ktensor. +% plus - Binary addition for ktensor. +% redistribute - Distribute lambda values to a specified mode. +% score - Checks if two ktensors match except for permutation. +% size - Size of ktensor. +% subsasgn - Subscripted assignement for ktensor. +% subsref - Subscripted reference for a ktensor. +% times - Element-wise multiplication for ktensor. +% tocell - Convert X to a cell array. +% ttm - Tensor times matrix for ktensor. +% ttv - Tensor times vector for ktensor. +% uminus - Unary minus for ktensor. +% uplus - Unary plus for a ktensor. diff --git a/external/tensor_toolbox_2.5/@ktensor/arrange.m b/external/tensor_toolbox_2.5/@ktensor/arrange.m new file mode 100755 index 0000000..7ace530 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/arrange.m @@ -0,0 +1,51 @@ +function X = arrange(X,foo) +%ARRANGE Arranges the rank-1 components of a ktensor. +% +% ARRANGE(X) normalizes the columns of the factor matrices and then sorts +% the ktensor components by magnitude, greatest to least. +% +% ARRANGE(X,N) absorbs the weights into the Nth factor matrix instead of +% lambda. +% +% ARRANGE(X,P) rearranges the components of X according to the +% permutation P. P should be a permutation of 1 to NCOMPOMENTS(X). +% +% See also KTENSOR, NCOMPONENTS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Just rearrange and return if second argument is a permutation +if exist('foo','var') && (length(foo) > 1) + X.lambda = X.lambda(foo); + for i = 1 : ndims(X) + X.u{i} = X.u{i}(:,foo); + end + return; +end + +%% Ensure that matrices are normalized +X = normalize(X); + +%% Sort +[X.lambda, idx] = sort(X.lambda, 1, 'descend'); +for i = 1 : ndims(X) + X.u{i} = X.u{i}(:,idx); +end + +%% Absorb the weight into one factor, if requested +if exist('foo','var') + r = length(X.lambda); + X.u{end} = X.u{end} * spdiags(X.lambda,0,r,r); + X.lambda = ones(size(X.lambda)); +end + diff --git a/external/tensor_toolbox_2.5/@ktensor/datadisp.m b/external/tensor_toolbox_2.5/@ktensor/datadisp.m new file mode 100755 index 0000000..4f29bd0 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/datadisp.m @@ -0,0 +1,119 @@ +function datadisp(T, dimlabels, opts) +%DATADISP Special display of a ktensor. +% +% DATADISP(T,LABELS) displays the largest positive entries of each rank-1 +% factor of T using the corresponding labels. LABELS is a cell array of +% size ndims(T) such that LABELS{n} is a string cell array of length +% size(T,n). +% +% DATADISP(T,LABELS,OPTS) specify options: +% OPTS.dimorder: Order to display the dimensions of T {1:ndims(T)} +% OPTS.maxentries: Number of entries to show for each factor {10} +% OPTS.printneg: Boolean to print the most negative entries {false} +% OPTS.threshold: Threshold of smallest magnitude score to show {1e-4} +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Fill in optional variable +if ~exist('opts','var') + opts = struct; +end + +%% Set options from input or use defaults +dimorder = setparam(opts,'dimorder',1:ndims(T)); +maxentries = setparam(opts,'maxentries',10); +printneg = setparam(opts,'printneg',false); +threshold = setparam(opts,'threshold',1e-6); + +%% Main loop +R = size(T.lambda,1); % Rank +r = 1; +while (r <= R) + + fprintf(1, '\n======== Group %d ========\n', r); + fprintf('\nWeight = %f\n', T.lambda(r)); + + for i = dimorder(1:end) + + print_sublist(T.u{i}(:,r), dimlabels{i}, 'positive', maxentries, threshold); + + if printneg + print_sublist(T.u{i}(:,r), dimlabels{i}, 'negative', maxentries, threshold); + end + + end + + if r == R, + break, + end; + + foo = input('\nReturn to continue, jump to rank, or ''0'' (zero) to quit: '); + if foo == 0 + return; + elseif isempty(foo) + r = r+1; + else + r = foo; + end +end + +return; + + +%% +function print_sublist(score, labels, type, maxentries, threshold) + +if isequal(type,'positive') + [sortedScore, sortedIdx] = sort(score, 'descend'); +elseif isequal(type, 'negative') + [sortedScore, sortedIdx] = sort(score, 'ascend'); +else + error('Invalid type'); +end + +sortedRefs = labels(sortedIdx); +entries = min([maxentries, length(score)]); + +if isequal(type,'positive') + range = 1:entries; +else + range = entries:-1:1; +end + +fprintf('%-10s %-4s %s\n','Score','Id','Name'); + +for k = range + if abs(sortedScore(k)) < threshold + continue; + end + if isequal(type,'negative') && sortedScore(k) >= 0 + continue; + end + if (abs(sortedScore(k)) < 1e-4) + fprintf(1, '%10.3e %4d %s\n', sortedScore(k), sortedIdx(k), ... + sortedRefs{k}); + else + fprintf(1, '%10.7f %4d %s\n', sortedScore(k), sortedIdx(k), ... + sortedRefs{k}); + end +end + +%% +function x = setparam(opts,name,default) +if isfield(opts,name); + x = opts.(name); +else + x = default; +end diff --git a/external/tensor_toolbox_2.5/@ktensor/disp.m b/external/tensor_toolbox_2.5/@ktensor/disp.m new file mode 100755 index 0000000..7df8ddf --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/disp.m @@ -0,0 +1,35 @@ +function disp(t, name) +%DISP Command window display for a ktensor. +% +% DISP(T) displays a Kruskal tensor with no name. +% +% DISP(T,NAME) display a Kruskal tensor with the given name. +% +% See also DISP, KTENSOR/DISPLAY, KTENSOR +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~exist('name','var') + name = 'ans'; +end + +fprintf('%s is a ktensor of size %s\n', name, tt_size2str(size(t))); +fprintf('\t%s.lambda = %s\n',name, ['[ ' num2str(t.lambda') ' ]'] ); + +if (ndims(t) > 0) + for j = 1 : ndims(t) + fprintf('\t%s.U{%d} = \n', name, j); + output = tt_matrix2cellstr(t.u{j}); + fprintf('\t\t%s\n',output{:}); + end +end diff --git a/external/tensor_toolbox_2.5/@ktensor/display.m b/external/tensor_toolbox_2.5/@ktensor/display.m new file mode 100755 index 0000000..7096a7d --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/display.m @@ -0,0 +1,20 @@ +function display(t) +%DISPLAY Command window display for a ktensor. +% +% DISPLAY(T) displays a Kruskal tensor with its name. +% +% See also DISPLAY, KTENSOR/DISP, KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +disp(t,inputname(1)); diff --git a/external/tensor_toolbox_2.5/@ktensor/double.m b/external/tensor_toolbox_2.5/@ktensor/double.m new file mode 100755 index 0000000..f0e6dc0 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/double.m @@ -0,0 +1,27 @@ +function A = double(X) +%DOUBLE Convert a ktensor to a double array. +% +% A = double(X) converts X to a standard multidimensional array. +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(X.lambda) % check for empty tensor + A = []; + return; +end + +sz = [size(X) 1]; +A = X.lambda' * khatrirao(X.u,'r')'; +A = reshape(A,sz); diff --git a/external/tensor_toolbox_2.5/@ktensor/end.m b/external/tensor_toolbox_2.5/@ktensor/end.m new file mode 100755 index 0000000..c2af10f --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/end.m @@ -0,0 +1,32 @@ +function e = end(X,k,n) +%END Last index of indexing expression for ktensor. +% +% The expression X(end,:,:) will call END(X,1,3) to determine +% the value of the first index. +% +% See also KTENSOR, KTENSOR/SUBSREF, END. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%TODO (after 2.0 release): Resolve ambiguity w.r.t X{end}and X(end,1,1) +%for 1st-order tensors. + +if n > ndims(X) + error('Subscript out of range.'); +end + +if (n ~= 1) + e = size(X,k); +else + e = ndims(X); +end diff --git a/external/tensor_toolbox_2.5/@ktensor/extract.m b/external/tensor_toolbox_2.5/@ktensor/extract.m new file mode 100755 index 0000000..90fb47d --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/extract.m @@ -0,0 +1,30 @@ +function new_X = extract(X,idx) +%EXTRACT Creates a new ktensor with only the specified components. +% +% Y = EXTRACT(X,S) selected the subset of components in X as defined by +% S. It should be the case that S is a subset of [1,...,NCOMPONENTS(X)]. +% +% See also KTENSOR, NCOMPONENTS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Set-up +N = ndims(X); +%% Extract +new_lambda = X.lambda(idx); +new_U = cell(N,1); +for i = 1 : N + new_U{i} = X.u{i}(:,idx); +end +new_X = ktensor(new_lambda, new_U); + diff --git a/external/tensor_toolbox_2.5/@ktensor/fixsigns.m b/external/tensor_toolbox_2.5/@ktensor/fixsigns.m new file mode 100755 index 0000000..017d05f --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/fixsigns.m @@ -0,0 +1,117 @@ +function K = fixsigns(K,K0) +%FIXSIGNS Fix sign ambiguity of a ktensor. +% +% K = FIXSIGNS(K) makes it so that the largest magnitude entries for +% each vector in each factor of K are positive, provided that the +% sign on *pairs* of vectors in a rank-1 component can be flipped. +% +% K = FIXSIGNS(K,K0) returns a version of K where some of the signs of +% the columns of the factor matrices have been flipped to better align +% with K0. +% +% See also KTENSOR and KTENSOR/ARRANGE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if nargin == 1 + K = fixsigns_oneargin(K); +else + K = fixsigns_twoargin(K, K0); +end + + +%% +function K = fixsigns_oneargin(K) +R = length(K.lambda); +for r = 1 : R + + for n = 1:ndims(K) + [val(n),idx(n)] = max(abs(K.u{n}(:,r))); + sgn(n) = sign(K.u{n}(idx(n),r)); + end + + negidx = find(sgn == -1); + nflip = 2 * floor(numel(negidx)/2); + + for i = 1:nflip + n = negidx(i); + K.u{n}(:,r) = -K.u{n}(:,r); + end + +end + +%% +function [A, best_sign] = fixsigns_twoargin(A,B) +% T. Kolda, November 2010. + +if ~isa(A,'ktensor') + A = ktensor(A); +end +if ~isa(B,'ktensor') + B = ktensor(B); +end +A = normalize(A); +B = normalize(B); + +N = ndims(A); +RA = ncomponents(A); +RB = ncomponents(B); + +%% Try to fix the signs for each component +best_sign = ones(N,RA); +for r = 1:RB + + % Compute the inner products. They should mostly be O(1) if there is a + % good match because the factors have prevsiouly been normalized. If + % the signs are correct, then the score should be +1. Otherwise we need + % to flip the sign and the score should be -1. + sgn_score = zeros(N,1); + for n = 1:N + sgn_score(n) = A{n}(:,r)' * B{n}(:,r); + end + + % Sort the sign scores. + [sort_sgn_score, sort_idx] = sort(sgn_score,'ascend'); + + % Determine the number of scores that should be flipped. + breakpt = find(sort_sgn_score < 0, 1, 'last'); + + % If nothing needs to be flipped, then move on the the next component. + if isempty(breakpt) + continue; + end + + % Need to flip signs in pairs. If we don't have an even number of + % negative sign scores, then we need to decide to do one fewer or one + % more. + if (mod(breakpt,2) == 0) + endpt = breakpt; + else + fprintf('Trouble fixing signs for mode %d\n', r); + if (breakpt < RB) && (-sort_sgn_score(breakpt) > sort_sgn_score(breakpt+1)) + endpt = breakpt + 1; + else + endpt = breakpt - 1; + end + end + + % Flip the signs + for i = 1:endpt + A{sort_idx(i)}(:,r) = -1 * A{sort_idx(i)}(:,r); + best_sign(sort_idx(i),r) = -1; + end + +end + + + diff --git a/external/tensor_toolbox_2.5/@ktensor/full (1).m b/external/tensor_toolbox_2.5/@ktensor/full (1).m new file mode 100755 index 0000000..37240ed --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/full (1).m @@ -0,0 +1,26 @@ +function t = full(t) +%FULL Convert a ktensor to a (dense) tensor. +% +% T = FULL(C) converts a ktensor to a (dense) tensor. +% +% Examples +% X = ktensor([3; 2], rand(4,2), rand(5,2), rand(3,2)); +% Y = full(A) %<-- equivalent dense tensor +% +% See also KTENSOR, TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +sz = size(t); +data = t.lambda' * khatrirao(t.u,'r')'; +t = tensor(data,sz); diff --git a/external/tensor_toolbox_2.5/@ktensor/full.m b/external/tensor_toolbox_2.5/@ktensor/full.m new file mode 100755 index 0000000..37240ed --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/full.m @@ -0,0 +1,26 @@ +function t = full(t) +%FULL Convert a ktensor to a (dense) tensor. +% +% T = FULL(C) converts a ktensor to a (dense) tensor. +% +% Examples +% X = ktensor([3; 2], rand(4,2), rand(5,2), rand(3,2)); +% Y = full(A) %<-- equivalent dense tensor +% +% See also KTENSOR, TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +sz = size(t); +data = t.lambda' * khatrirao(t.u,'r')'; +t = tensor(data,sz); diff --git a/external/tensor_toolbox_2.5/@ktensor/innerprod.m b/external/tensor_toolbox_2.5/@ktensor/innerprod.m new file mode 100755 index 0000000..84d35bf --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/innerprod.m @@ -0,0 +1,53 @@ +function res = innerprod(X,Y) +%INNERPROD Efficient inner product with a ktensor. +% +% R = INNERPROD(X,Y) efficiently computes the inner product between +% two tensors X and Y. If Y is a ktensor, the inner product is +% computed using inner products of the factor matrices, X{i}'*Y{i}. +% Otherwise, the inner product is computed using ttv with all of +% the columns of X's factor matrices, X{i}. +% +% See also KTENSOR, KTENSOR/TTV +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~isequal(size(X),size(Y)) + error('X and Y must be the same size.'); +end + +% X is a ktensor +switch class(Y) + + case {'ktensor'} + M = X.lambda * Y.lambda'; + for n = 1:ndims(X) + M = M .* (X.u{n}' * Y.u{n}); + end + res = sum(M(:)); + + case {'tensor','sptensor','ttensor'} + R = length(X.lambda); + vecs = cell(1,ndims(X)); + res = 0; + for r = 1:R + for n = 1:ndims(X) + vecs{n} = X.u{n}(:,r); + end + res = res + X.lambda(r) * ttv(Y,vecs); + end + + otherwise + disp(['Inner product not available for class ' class(Y)]); +end + +return; diff --git a/external/tensor_toolbox_2.5/@ktensor/isequal.m b/external/tensor_toolbox_2.5/@ktensor/isequal.m new file mode 100755 index 0000000..d371dbd --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/isequal.m @@ -0,0 +1,28 @@ +function [tf, tf_lambda, tf_U] = isequal(A,B) +%ISEQUAL True if each component of two ktensor's is numerically equal. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +tf = false; +tf_lambda = false; +tf_U = false; + +if ~isa(B,'ktensor') + return; +end + +tf_lambda = isequal(A.lambda, B.lambda); +if ncomponents(A) == ncomponents(B) + tf_U = cellfun(@isequal, A.u, B.u); +end +tf = tf_lambda & all(tf_U); + diff --git a/external/tensor_toolbox_2.5/@ktensor/ktensor.m b/external/tensor_toolbox_2.5/@ktensor/ktensor.m new file mode 100755 index 0000000..fb546f0 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/ktensor.m @@ -0,0 +1,89 @@ +function t = ktensor(varargin) +%KTENSOR Tensor stored as a Kruskal operator (decomposed). +% +% K = KTENSOR(lambda,U1,U2,...,UM) creates a Kruskal tensor from its +% constituent parts. Here lambda is a k-vector and each Um is a +% matrix with k columns. +% +% K = KTENSOR(lambda, U) is the same as above except that U is a +% cell array containing matrix Um in cell m. +% +% K = KTENSOR(U) assumes U is a cell array containing matrix Um in +% cell m and assigns the weight of each factor to be one. +% +% K = KTENSOR(T) creates a ktensor by copying an existing ktensor. +% +% Examples +% K = ktensor([3; 2], rand(4,2), rand(5,2), rand(3,2)) +% +% See also TENSOR, TTENSOR, KTENSOR/FULL. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% EMPTY CONSTRUCTOR +if nargin == 0 + t.lambda = []; + t.u = {}; + t = class(t,'ktensor'); + return; +end + +% Copy CONSTRUCTOR +if (nargin == 1) && isa(varargin{1}, 'ktensor') + t.lambda = varargin{1}.lambda; + t.u = varargin{1}.u; + t = class(t, 'ktensor'); + return; +end + +if isa(varargin{1},'cell') + + u = varargin{1}; + t.lambda = ones(size(u{1},2),1); + t.u = u; + +else + + t.lambda = varargin{1}; + if ~isa(t.lambda,'numeric') || ndims(t.lambda) ~=2 || size(t.lambda,2) ~= 1 + error('LAMBDA must be a column vector.'); + end + + if isa(varargin{2},'cell') + t.u = varargin{2}; + else + for i = 2 : nargin + t.u{i-1} = varargin{i}; + end + end + +end + + +% Check that each Um is indeed a matrix +for i = 1 : length(t.u) + if ndims(t.u{i}) ~= 2 + error(['Matrix U' int2str(i) ' is not a matrix!']); + end +end + +% Size error checking +k = length(t.lambda); +for i = 1 : length(t.u) + if size(t.u{i},2) ~= k + error(['Matrix U' int2str(i) ' does not have ' int2str(k) ' columns.']); + end +end + +t = class(t, 'ktensor'); +return; diff --git a/external/tensor_toolbox_2.5/@ktensor/minus.m b/external/tensor_toolbox_2.5/@ktensor/minus.m new file mode 100755 index 0000000..e071b60 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/minus.m @@ -0,0 +1,45 @@ +function C = minus(A,B) +%MINUS Binary subtraction for ktensor. +% +% C = MINUS(A,B) computes C = A - B. A and B must both be ktensors +% and have the same size, and the result is another ktensor of the +% same size. +% +% C = MINUS(A,B) is called for the syntax 'A - B' when A or B is a +% ktensor. +% +% See also KTENSOR, SIZE, ISEQUAL. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if (isa(A,'ktensor') && isa(B,'ktensor')) + + if ~isequal(size(A),size(B)) + error('Tensor size mismatch.') + end + + lambda = [A.lambda; -B.lambda]; + M = ndims(A); + u = cell(M,1); + for m = 1 : M + u{m} = [A.u{m} B.u{m}]; + end + C = ktensor(lambda,u); + return; + +end + +error('Use minus(full(A),full(B)).'); + + + diff --git a/external/tensor_toolbox_2.5/@ktensor/mtimes.m b/external/tensor_toolbox_2.5/@ktensor/mtimes.m new file mode 100755 index 0000000..e3073e1 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/mtimes.m @@ -0,0 +1,30 @@ +function C = mtimes(A,B) +%MTIMES Implement A*B (scalar multiply) for ktensor. +% +% C = mtimes(A,B) computes A * B where A is a Kruskal tensor and B is +% a scalar (or vice versa). The result C is the same size as A. +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Note: We can do scalar times a tensor, but anything more complex is +% an error. + +if isa(B,'numeric') && isequal(size(B),[1 1]) + C = ktensor(B * A.lambda, A.u); +elseif isa(A,'numeric') && isequal(size(A),[1 1]) + C = ktensor(A * B.lambda, B.u); +else + error('Use mtimes(full(A),full(B)).'); +end diff --git a/external/tensor_toolbox_2.5/@ktensor/mttkrp.m b/external/tensor_toolbox_2.5/@ktensor/mttkrp.m new file mode 100755 index 0000000..ac9722d --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/mttkrp.m @@ -0,0 +1,39 @@ +function V = mttkrp(X,U,n) +%MTTKRP Matricized tensor times Khatri-Rao product for ktensor. +% +% V = MTTKRP(X,U,n) efficiently calculates the matrix product of the +% n-mode matricization of X with the Khatri-Rao product of all +% entries in U, a cell array of matrices, except the nth. How to +% most efficiently do this computation depends on the type of tensor +% involved. +% +% See also KTENSOR, KTENSOR/TTV +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +N = ndims(X); + +if (n==1) + R = size(U{2},2); +else + R = size(U{1},2); +end + +% Compute matrix of weights +W = repmat(X.lambda,1,R); +for i = [1:n-1,n+1:N] + W = W .* (X.u{i}' * U{i}); +end + +% Find each column of answer by multiplying columns of X.u{n} with weights +V = X.u{n} * W; diff --git a/external/tensor_toolbox_2.5/@ktensor/ncomponents.m b/external/tensor_toolbox_2.5/@ktensor/ncomponents.m new file mode 100755 index 0000000..db0ceff --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/ncomponents.m @@ -0,0 +1,20 @@ +function n = ncomponents(t) +%NCOMPONENTS Number of components for a ktensor. +% +% NCOMPONENTS(T) returns the number of compontents in the ktensor T. +% +% See also KTENSOR +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +n = length(t.lambda); diff --git a/external/tensor_toolbox_2.5/@ktensor/ndims.m b/external/tensor_toolbox_2.5/@ktensor/ndims.m new file mode 100755 index 0000000..8ae16e8 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/ndims.m @@ -0,0 +1,20 @@ +function n = ndims(t) +%NDIMS Number of dimensions for a ktensor. +% +% NDIMS(T) returns the number of dimensions of tensor T. +% +% See also KTENSOR +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +n = numel(t.u); diff --git a/external/tensor_toolbox_2.5/@ktensor/norm.m b/external/tensor_toolbox_2.5/@ktensor/norm.m new file mode 100755 index 0000000..ea18a76 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/norm.m @@ -0,0 +1,31 @@ +function nrm = norm(A) +%NORM Frobenius norm of a ktensor. +% +% NORM(T) returns the Frobenius norm of a ktensor. +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Retrieve the factors of A +U = A.u; + +% Compute the matrix of correlation coefficients +coefMatrix = A.lambda * A.lambda'; +for i = 1:ndims(A) + coefMatrix = coefMatrix .* (U{i}'*U{i}); +end + +nrm = sqrt(abs(sum(coefMatrix(:)))); + +return; diff --git a/external/tensor_toolbox_2.5/@ktensor/normalize.m b/external/tensor_toolbox_2.5/@ktensor/normalize.m new file mode 100755 index 0000000..150fcd6 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/normalize.m @@ -0,0 +1,97 @@ +function X = normalize(X,N,normtype,mode) +%NORMALIZE Normalizes the columns of the factor matrices. +% +% NORMALIZE(X) normalizes the columns of each factor matrix, absorbing +% the excess weight into lambda. Also ensures that lambda is positive. +% +% NORMALIZE(X,N) absorbs the weights into the Nth factor matrix instead +% of lambda. (All the lambda values are 1.) +% +% NORMALIZE(X,0) equally divides the weights across the factor matrices. +% (All the lambda values are 1.) +% +% NORMALIZE(X,[]) is equivalent to NORMALIZE(X). +% +% NORMALIZE(X,'sort') is the same as the above except it sorts the +% components by lambda value, from greatest to least. +% +% NORMALIZE(X,V,1) normalizes using the vector one norm (sum(abs(x)) +% rather than the two norm (sqrt(sum(x.^2))), where V can be any of the +% second arguments decribed above. +% +% NORMALIZE(X,[],1,I) just normalizes the I-th factor using whatever norm +% is specified by the 3rd argument (1 or 2). +% +% See also KTENSOR, NCOMPONENTS, ARRANGE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% +if ~exist('N','var') + N = -1; +end + +if isempty(N) + N = -1; +end + +if isequal(N,'sort') + N = -2; +end + +if ~exist('normtype','var') + normtype = 2; +end + +if exist('mode', 'var') + for r = 1:length(X.lambda) + tmp = norm(X.u{mode}(:,r),normtype); + if (tmp > 0) + X.u{mode}(:,r) = X.u{mode}(:,r) / tmp; + end + X.lambda(r) = X.lambda(r) * tmp; + end + return; +end + +%% Ensure that matrices are normalized +for r = 1:length(X.lambda) + for n = 1:ndims(X) + tmp = norm(X.u{n}(:,r),normtype); + if (tmp > 0) + X.u{n}(:,r) = X.u{n}(:,r) / tmp; + end + X.lambda(r) = X.lambda(r) * tmp; + end +end + +%% Check that all the lambda values are positive +idx = find(X.lambda < 0); +X.u{1}(:,idx) = -1 * X.u{1}(:,idx); +X.lambda(idx) = -1 * X.lambda(idx); + +%% Absorb the weight into one factor, if requested +if (N == 0) + D = diag(nthroot(X.lambda,ndims(X))); + X.u = cellfun(@(x) x*D, X.u, 'UniformOutput', false); + X.lambda = ones(size(X.lambda)); +elseif (N > 0) + X.u{N} = X.u{N} * diag(X.lambda); + X.lambda = ones(size(X.lambda)); +elseif (N == -2) + [~,p] = sort(X.lambda,'descend'); + X = arrange(X,p); +end + + + diff --git a/external/tensor_toolbox_2.5/@ktensor/nvecs.m b/external/tensor_toolbox_2.5/@ktensor/nvecs.m new file mode 100755 index 0000000..09ed514 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/nvecs.m @@ -0,0 +1,65 @@ +function u = nvecs(X,n,r,opts) +%NVECS Compute the leading mode-n vectors for a ktensor. +% +% U = NVECS(X,n,r) computes the r leading eigenvalues of Xn*Xn' +% (where Xn is the mode-n matricization of X), which provides +% information about the mode-n fibers. In two-dimensions, the r +% leading mode-1 vectors are the same as the r left singular vectors +% and the r leading mode-2 vectors are the same as the r right +% singular vectors. +% +% U = NVECS(X,n,r,OPTS) specifies options: +% OPTS.eigsopts: options passed to the EIGS routine [struct('disp',0)] +% OPTS.flipsign: make each column's largest element positive [true] +% +% See also KTENSOR, TENMAT, EIGS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~exist('opts','var') + opts = struct; +end + +if isfield(opts,'eigsopts') + eigsopts = opts.eigsopts; +else + eigsopts.disp = 0; +end + +% Compute Xn * Xn' excluding the nth factor +M = X.lambda * X.lambda'; +for i = 1:ndims(X) + if i == n, continue, end; + M = M .* (X.u{i}' * X.u{i}); +end + +% Compute Xn * Xn' +Y = X.u{n} * M * X.u{n}'; + +[u,d] = eigs(Y, r, 'LM', eigsopts); + +if isfield(opts,'flipsign') + flipsign = opts.flipsign; +else + flipsign = true; +end + +if flipsign + % Make the largest magnitude element be positive + [val,loc] = max(abs(u)); + for i = 1:r + if u(loc(i),i) < 0 + u(:,i) = u(:,i) * -1; + end + end +end diff --git a/external/tensor_toolbox_2.5/@ktensor/permute.m b/external/tensor_toolbox_2.5/@ktensor/permute.m new file mode 100755 index 0000000..40d1180 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/permute.m @@ -0,0 +1,34 @@ +function b = permute(a,order) +%PERMUTE Permute dimensions of a ktensor. +% +% B = PERMUTE(A,ORDER) rearranges the dimensions of A so that they +% are in the order specified by the vector ORDER. The tensor +% produced has the same values of A but the order of the subscripts +% needed to access any particular element are rearranged as +% specified by ORDER. +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +N = ndims(a); + +if ~isequal(1:N,sort(order)) + error('Invalid permuation'); +end + +b = ktensor(a.lambda, a.u(order)); + + + + diff --git a/external/tensor_toolbox_2.5/@ktensor/plus.m b/external/tensor_toolbox_2.5/@ktensor/plus.m new file mode 100755 index 0000000..affdfdb --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/plus.m @@ -0,0 +1,37 @@ +function C = plus(A,B) +%PLUS Binary addition for ktensor. +% +% C = PLUS(A,B) adds two ktensors of the same size, and the +% result is a ktensor of the same size. +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if (isa(A,'ktensor') && isa(B,'ktensor')) + + if ~isequal(size(A),size(B)) + error('Tensor size mismatch.') + end + + lambda = [A.lambda; B.lambda]; + M = ndims(A); + u = cell(M,1); + for m = 1 : M + u{m} = [A.u{m} B.u{m}]; + end + C = ktensor(lambda, u); + return; +end + +error('Use plus(full(A),full(B)).'); diff --git a/external/tensor_toolbox_2.5/@ktensor/redistribute.m b/external/tensor_toolbox_2.5/@ktensor/redistribute.m new file mode 100755 index 0000000..b8d887d --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/redistribute.m @@ -0,0 +1,23 @@ +function X = redistribute(X,mode) +%REDISTRIBUTE Distribute lambda values to a specified mode. +% +% K = REDISTRIBUTE(K,N) absorbs the weights from the lambda vector +% into mode N. Set the lambda vector to all ones. +% +% See also KTENSOR, NORMALIZE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +for r = 1:length(X.lambda) + X.u{mode}(:,r) = X.u{mode}(:,r) * X.lambda(r); + X.lambda(r) = 1; +end diff --git a/external/tensor_toolbox_2.5/@ktensor/score.m b/external/tensor_toolbox_2.5/@ktensor/score.m new file mode 100755 index 0000000..e47df66 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/score.m @@ -0,0 +1,173 @@ +function [best_score, A, flag, best_perm] = score(A,B,varargin) +%SCORE Checks if two ktensors match except for permutation. +% +% SCORE(A,B) returns the score of the match between A and B where +% A is trying to be matched against B. +% +% We define matching as follows. If A and B are single component ktensors +% that have been normalized so that their weights are lambda_a and +% lambda_b, then the score is defined as +% +% score = penalty * (a1'*b1) * (a2'*b2) * ... * (aR'*bR), +% +% where the penalty is defined by the lambda values such that +% +% penalty = 1 - abs(lambda_a - lambda_b) / max(lamdba_a, lambda_b). +% +% The score of multi-components ktensors is a normalized sum of the +% scores across the best permutation of the components of A. A can have +% more components than B --- any extra components are ignored in terms of +% the matching score. +% +% [SCORE,A] = SCORE(...) also returns A which has been normalized +% and permuted to best match B. +% +% [SCORE,A,FLAG] = SCORE(...) also returns a boolean to indicate +% a match according to a user-specified threshold. +% +% [SCORE,A,FLAG,PERM] = SCORE(...) also returns the permutation +% of the components of A that was used to best match B. +% +% SCORE(A,B,'param',value,...) takes the following parameters... +% +% 'lambda_penalty' - Boolean indicating whether or not to consider the +% lambda values in the calculations. {true} +% +% 'threshold' - Threshold specified in the formula above for +% deteriming a match. {0.99^N where N = ndims(A)}. +% +% 'greedy' - Boolean indicating whether or not to consider all +% possible matchings (expotentially expensive) or just do a greedy +% matching. {false} +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +% E. Acar & T. Kolda, 2010. + +%% Make sure A and B are ktensors +if ~isa(A,'ktensor') + A = ktensor(A); +end +if ~isa(B,'ktensor') + B = ktensor(B); +end + +%% Error checking +if ~isequal(size(A),size(B)) + error('Size mismatch'); +end + +%% Set-up +N = ndims(A); +RA = ncomponents(A); +RB = ncomponents(B); + +%% We're matching components in A to B +if (RA < RB) + error('Tensor A must have at least as many components as tensor B.'); +end + +%% Parse parameters +params = inputParser; +params.addParamValue('lambda_penalty', true, @islogical); +params.addParamValue('greedy', false, @islogical); +params.addParamValue('threshold', 0.99^N, @(x)(x<1)); +params.parse(varargin{:}); + +%% Make sure columns of factor matrices in A and B are normalized +A = normalize(A); +B = normalize(B); + +%% Compute all possible vector-vector congruences. + +% Compute every pair for each mode +Cbig = tenzeros([RA,RB,N]); +for n = 1:N + Cbig(:,:,n) = abs(A.u{n}' * B.u{n}); +end + +% Collapse across all modes using the product +C = collapse(Cbig,3,@prod); + +%% Calculate penalty based on differences in the Lambda's +% Note that we are assuming the the lambda value are positive because the +% ktensor's were previously normalized. +if (params.Results.lambda_penalty) + P = zeros(RA,RB); + for ra = 1:RA + la = A.lambda(ra); + for rb = 1:RB + lb = B.lambda(rb); + P(ra,rb) = 1 - (abs(la-lb) / max(la,lb)); + end + end + C = P.*C; +end + +%% Option to do greedy matching +if (params.Results.greedy) + + best_perm = zeros(1,RA); + best_score = 0; + for r = 1:RB + [~,idx] = max(C(:)); + [i,j] = ind2sub([RA RB], idx); + best_score = best_score + C(i,j); + C(i,:) = 0; + C(:,j) = 0; + best_perm(j) = i; + end + best_score = best_score / RB; + flag = 1; + + % Rearrange the components of A according to the best matching + foo = 1:RA; + tf = ismember(foo,best_perm); + best_perm(RB+1:RA) = foo(~tf); + A = arrange(A, best_perm); + return; +end + +%% Compute all possible matchings +% Creates a matrix P where each row is a possible matching of components in +% A to components of B. We assume A has at least as many components as B. +idx = nchoosek(1:RA,RB); +M = []; +for i = 1:size(idx,1) + M = [M; perms(idx(i,:))]; %#ok +end + +%% Calculate the congruences for each matching +scores = zeros(size(M)); +for i = 1:size(M,1) + for r = 1:RB + scores(i,r) = C(M(i,r),r); + end +end + +%% Figure out the best matching based on sum's across the components +score = sum(scores,2)/RB; +[best_score, max_score_id] = max(score); +if min(scores(max_score_id,:)) >= params.Results.threshold + flag = 1; +else + flag = 0; +end +best_match = M(max_score_id,:); +best_perm = [best_match setdiff(1:RA, best_match)]; + +%% Rearrange the components of A according to the best matching +A = arrange(A, best_perm); + + diff --git a/external/tensor_toolbox_2.5/@ktensor/size.m b/external/tensor_toolbox_2.5/@ktensor/size.m new file mode 100755 index 0000000..84af0de --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/size.m @@ -0,0 +1,33 @@ +function m = size(t,idx) +%SIZE Size of ktensor. +% +% D = SIZE(T) returns the size of the tensor. +% +% I = SIZE(T,DIM) returns the size of the dimension specified by +% the scalar DIM. +% +% See also KTENSOR, KTENSOR/NDIMS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(t.lambda) + m = []; +end + +if exist('idx','var') + m = size(t.u{idx}, 1); +else + for i = 1 : ndims(t) + m(i) = size(t.u{i}, 1); + end +end diff --git a/external/tensor_toolbox_2.5/@ktensor/subsasgn.m b/external/tensor_toolbox_2.5/@ktensor/subsasgn.m new file mode 100755 index 0000000..2f55d7a --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/subsasgn.m @@ -0,0 +1,49 @@ +function t = subsasgn(t,s,b) +%SUBSASGN Subscripted assignement for ktensor. +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +switch s(1).type + case '.' + switch s(1).subs + case 'lambda' + if length(s) == 1 + t = ktensor(b, t.u); + else + newlambda = subsasgn(t.lambda, s(2:end), b); + t = ktensor(newlambda, t.u); + end + case {'u','U'} + if length(s) == 1 + t = ktensor(t.lambda, b); + else + tmpu = subsasgn(t.u, s(2:end), b); + t = ktensor(t.lambda, tmpu); + end + otherwise + error(['No such field: ', s(1).subs]); + end + case '()' + error('Cannot change individual entries in a ktensor.') + case '{}' + new_s(1).type = '.'; + new_s(1).subs = 'u'; + new_s(2:length(s)+1) = s; + t = subsasgn(t, new_s, b); + otherwise + error('Invalid subsasgn.'); +end + + diff --git a/external/tensor_toolbox_2.5/@ktensor/subsref.m b/external/tensor_toolbox_2.5/@ktensor/subsref.m new file mode 100755 index 0000000..3023718 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/subsref.m @@ -0,0 +1,48 @@ +function a = subsref(t,s) +%SUBSREF Subscripted reference for a ktensor. +% +% Examples +% X = ktensor([3; 2], rand(4,2), rand(5,2), rand(3,2)); +% X.lambda returns the lambda array ([3;2]). +% X.U returns a cell array of 3 matrices. +% X.U{1} returns the matrix corresponding to the first mode. +% X(2,3,1) calculates and returns that single element of A. +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +switch s(1).type + case '.' + switch s(1).subs + case 'lambda' + a = tt_subsubsref(t.lambda,s); + case {'u','U'} + a = tt_subsubsref(t.u,s); + otherwise + error(['No such field: ', s(1).subs]); + end + case '()' + a = 0; + for k = 1 : length(t.lambda) + b = t.lambda(k); + for i = 1 : length(s.subs) + b = b * t.u{i}(s.subs{i},k); + end + a = a + b; + end + case '{}' + a = subsref(t.u,s); + otherwise + error('Invalid subsref.'); +end diff --git a/external/tensor_toolbox_2.5/@ktensor/times.m b/external/tensor_toolbox_2.5/@ktensor/times.m new file mode 100755 index 0000000..63cddf1 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/times.m @@ -0,0 +1,34 @@ +function C = times(A,B) +%TIMES Element-wise multiplication for ktensor. +% +% TIMES(A,B) denotes element-by-element multiplication. +% +% C = TIMES(A,B) is called for the syntax 'A .* B' when A or B is a +% tensor. +% +% See also KTENSOR, SPTENSOR/TIMES. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~isequal(size(A),size(B)) + error('Must be two tensors of the same size'); +end + +switch class(B) + case {'sptensor','tensor'} + % Call back to sptensor version. + C = times(B,A); + return; + otherwise + error('Invalid second argument for ktensor/times'); +end diff --git a/external/tensor_toolbox_2.5/@ktensor/tocell.m b/external/tensor_toolbox_2.5/@ktensor/tocell.m new file mode 100755 index 0000000..59dc12f --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/tocell.m @@ -0,0 +1,43 @@ +function U = tocell(X,N) +%TOCELL Convert X to a cell array. +% +% TOCELL(X) converts X to a cell array, evenly distributing the +% weight in lambda. +% +% TOCELL(X,N) absorbs the weights into the Nth factor matrix. +% +% See also KTENSOR, NORMALIZE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if exist('N','var') + X = normalize(X,N); + U = X.u; + return; +end + +if isequal(X.lambda,ones(size(X.lambda))) + U = X.u; + return; +end + + +lsplit = nthroot(X.lambda,ndims(X)); +R = length(X.lambda); +U = X.u; +D = diag(lsplit); +for n = 1:ndims(X) + U{n} = U{n} * D; +end + + diff --git a/external/tensor_toolbox_2.5/@ktensor/ttm (1).m b/external/tensor_toolbox_2.5/@ktensor/ttm (1).m new file mode 100755 index 0000000..a478d0f --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/ttm (1).m @@ -0,0 +1,110 @@ +function X = ttm(X,V,varargin) +%TTM Tensor times matrix for ktensor. +% +% Y = TTM(X,A,N) computes the n-mode product of the ktensor X with a +% matrix A; i.e., X x_N A. The integer N specifies the dimension +% (or mode) of X along which A should be multiplied. If size(A) = +% [J,I], then X must have size(X,N) = I. The result will be a +% ktensor of the same order and size as X except that size(Y,N) = J. +% +% Y = TTM(X,{A,B,C,...}) computes the n-mode product of the ktensor +% X with a sequence of matrices in the cell array. The n-mode +% products are computed sequentially along all dimensions (or modes) +% of X. The cell array contains ndims(X) matrices. +% +% Y = TTM(X,{A,B,C,...},DIMS) computes the sequence tensor-matrix +% products along the dimensions specified by DIMS. +% +% Y = TTM(...,'t') performs the same computations as above except +% the matrices are transposed. +% +% Examples +% X = ktensor({rand(5,2),rand(3,2),rand(4,2),rand(2,2)}); +% A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2); +% Y = ttm(X, A, 1) %<-- computes X times A in mode-1 +% Y = ttm(X, {A,B,C,D}, 1) %<-- same as above +% Y = ttm(X, A', 1, 't') %<-- same as above +% Y = ttm(X, {A,B,C,D}, [1 2 3 4]) %<-- 4-way multiply +% Y = ttm(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above +% Y = ttm(X, {A,B,C,D}) %<-- same as above +% Y = ttm(X, {A',B',C',D'}, 't') %<-- same as above +% Y = ttm(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4 +% Y = ttm(X, {A,B,C,D}, [3 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, [1 2 4]) %<-- 3-way multiply +% Y = ttm(X, {A,B,C,D}, [1 2 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, -3) %<-- same as above +% Y = ttm(X, {A,B,C,D}, -3) %<-- same as above +% +% See also KTENSOR, KTENSOR/ARRANGE, TENSOR/TTM +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +%%%%%%%%%%%%%%%%%%%%%% +%%% ERROR CHECKING %%% +%%%%%%%%%%%%%%%%%%%%%% + +% Check the number of arguments +if (nargin < 2) + error('TTM requires at least two arguments.'); +end + +% Check for transpose option +isTranspose = false; +if numel(varargin) > 0 + if isnumeric(varargin{1}); + dims = varargin{1}; + end + isTranspose = (ischar(varargin{end}) && (varargin{end} == 't')); +end + +% Check for dims argument +if ~exist('dims','var') + dims = []; +end + +% Check that 2nd argument is cell array. If not, recall with V as a +% cell array with one element. +if ~iscell(V) + X = ttm(X,{V},dims,varargin{end}); + return; +end + +% Get sorted dims and index for multiplicands +[dims,vidx] = tt_dimscheck(dims,ndims(X),numel(V)); + +% Determine correct size index +if isTranspose + j = 1; +else + j = 2; +end + +% Check that each multiplicand is the right size. +for i = 1:numel(dims) + if (ndims(V) ~= 2) || (size(V{vidx(i)},j) ~= size(X,dims(i))) +disp(size(V{vidx(i)})) +disp(size(X)) + + error('Multiplicand is wrong size'); + end +end + +% Do the multiplications in the specified modes. +for i = 1:numel(dims) + if isTranspose + X.u{dims(i)} = V{vidx(i)}'* X.u{dims(i)}; + else + X.u{dims(i)} = V{vidx(i)} * X.u{dims(i)}; + end +end diff --git a/external/tensor_toolbox_2.5/@ktensor/ttm.m b/external/tensor_toolbox_2.5/@ktensor/ttm.m new file mode 100755 index 0000000..a478d0f --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/ttm.m @@ -0,0 +1,110 @@ +function X = ttm(X,V,varargin) +%TTM Tensor times matrix for ktensor. +% +% Y = TTM(X,A,N) computes the n-mode product of the ktensor X with a +% matrix A; i.e., X x_N A. The integer N specifies the dimension +% (or mode) of X along which A should be multiplied. If size(A) = +% [J,I], then X must have size(X,N) = I. The result will be a +% ktensor of the same order and size as X except that size(Y,N) = J. +% +% Y = TTM(X,{A,B,C,...}) computes the n-mode product of the ktensor +% X with a sequence of matrices in the cell array. The n-mode +% products are computed sequentially along all dimensions (or modes) +% of X. The cell array contains ndims(X) matrices. +% +% Y = TTM(X,{A,B,C,...},DIMS) computes the sequence tensor-matrix +% products along the dimensions specified by DIMS. +% +% Y = TTM(...,'t') performs the same computations as above except +% the matrices are transposed. +% +% Examples +% X = ktensor({rand(5,2),rand(3,2),rand(4,2),rand(2,2)}); +% A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2); +% Y = ttm(X, A, 1) %<-- computes X times A in mode-1 +% Y = ttm(X, {A,B,C,D}, 1) %<-- same as above +% Y = ttm(X, A', 1, 't') %<-- same as above +% Y = ttm(X, {A,B,C,D}, [1 2 3 4]) %<-- 4-way multiply +% Y = ttm(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above +% Y = ttm(X, {A,B,C,D}) %<-- same as above +% Y = ttm(X, {A',B',C',D'}, 't') %<-- same as above +% Y = ttm(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4 +% Y = ttm(X, {A,B,C,D}, [3 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, [1 2 4]) %<-- 3-way multiply +% Y = ttm(X, {A,B,C,D}, [1 2 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, -3) %<-- same as above +% Y = ttm(X, {A,B,C,D}, -3) %<-- same as above +% +% See also KTENSOR, KTENSOR/ARRANGE, TENSOR/TTM +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +%%%%%%%%%%%%%%%%%%%%%% +%%% ERROR CHECKING %%% +%%%%%%%%%%%%%%%%%%%%%% + +% Check the number of arguments +if (nargin < 2) + error('TTM requires at least two arguments.'); +end + +% Check for transpose option +isTranspose = false; +if numel(varargin) > 0 + if isnumeric(varargin{1}); + dims = varargin{1}; + end + isTranspose = (ischar(varargin{end}) && (varargin{end} == 't')); +end + +% Check for dims argument +if ~exist('dims','var') + dims = []; +end + +% Check that 2nd argument is cell array. If not, recall with V as a +% cell array with one element. +if ~iscell(V) + X = ttm(X,{V},dims,varargin{end}); + return; +end + +% Get sorted dims and index for multiplicands +[dims,vidx] = tt_dimscheck(dims,ndims(X),numel(V)); + +% Determine correct size index +if isTranspose + j = 1; +else + j = 2; +end + +% Check that each multiplicand is the right size. +for i = 1:numel(dims) + if (ndims(V) ~= 2) || (size(V{vidx(i)},j) ~= size(X,dims(i))) +disp(size(V{vidx(i)})) +disp(size(X)) + + error('Multiplicand is wrong size'); + end +end + +% Do the multiplications in the specified modes. +for i = 1:numel(dims) + if isTranspose + X.u{dims(i)} = V{vidx(i)}'* X.u{dims(i)}; + else + X.u{dims(i)} = V{vidx(i)} * X.u{dims(i)}; + end +end diff --git a/external/tensor_toolbox_2.5/@ktensor/ttv.m b/external/tensor_toolbox_2.5/@ktensor/ttv.m new file mode 100755 index 0000000..72f236a --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/ttv.m @@ -0,0 +1,77 @@ +function c = ttv(a,v,dims) +%TTV Tensor times vector for ktensor. +% +% Y = TTV(X,A,N) computes the product of Kruskal tensor X with a +% (column) vector A. The integer N specifies the dimension in X +% along which A is multiplied. If size(A) = [I,1], then X must have +% size(X,N) = I. Note that ndims(Y) = ndims(X) - 1 because the N-th +% dimension is removed. +% +% Y = TTV(X,{A1,A2,...}) computes the product of tensor X with a +% sequence of vectors in the cell array. The products are computed +% sequentially along all dimensions (or modes) of X. The cell array +% contains ndims(X) vectors. +% +% Y = TTV(X,{A1,A2,...},DIMS) computes the sequence tensor-vector +% products along the dimensions specified by DIMS. +% +% See also TENSOR/TTV, KTENSOR, KTENSOR/TTM. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%%%%%%%%%%%%%%%%%%%%%% +%%% ERROR CHECKING %%% +%%%%%%%%%%%%%%%%%%%%%% + +% Check the number of arguments +if (nargin < 2) + error('TTV requires at least two arguments.'); +end + +% Check for 3rd argument +if ~exist('dims','var') + dims = []; +end + +% Check that 2nd argument is cell array. If not, recall with v as a +% cell array with one element. +if ~iscell(v) + c = ttv(a,{v},dims); + return; +end + +% Get sorted dims and index for multiplicands +[dims,vidx] = tt_dimscheck(dims,ndims(a),numel(v)); + +% Check that each multiplicand is the right size. +for i = 1:numel(dims) + if ~isequal(size(v{vidx(i)}),[size(a,dims(i)) 1]) + error('Multiplicand is wrong size'); + end +end + +% Figure out which dimensions will be left when we're done +remdims = setdiff(1:ndims(a),dims); + +% Collapse dimensions that are being multiplied out +newlambda = a.lambda; +for i = 1:numel(dims) + newlambda = newlambda .* ( a.u{dims(i)}' * v{vidx(i)} ); +end + +% Create final result +if isempty(remdims) + c = sum(newlambda); +else + c = ktensor(newlambda,a.u{remdims}); +end diff --git a/external/tensor_toolbox_2.5/@ktensor/uminus.m b/external/tensor_toolbox_2.5/@ktensor/uminus.m new file mode 100755 index 0000000..f42ada1 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/uminus.m @@ -0,0 +1,18 @@ +function t = uminus(t) +%UMINUS Unary minus for ktensor. +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +t.lambda = -t.lambda; diff --git a/external/tensor_toolbox_2.5/@ktensor/uplus.m b/external/tensor_toolbox_2.5/@ktensor/uplus.m new file mode 100755 index 0000000..3498ec7 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ktensor/uplus.m @@ -0,0 +1,19 @@ +function t = uplus(t) +%UPLUS Unary plus for a ktensor. +% +% See also KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% This function does nothing! + diff --git a/external/tensor_toolbox_2.5/@sptenmat/Contents.m b/external/tensor_toolbox_2.5/@sptenmat/Contents.m new file mode 100755 index 0000000..750ec6e --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/Contents.m @@ -0,0 +1,18 @@ +% @SPTENMAT +% +% Files +% aatx - Implicitly compute A * A' * x for sptenmat. +% disp - Command window display of a sptenmat. +% display - Command window display of a sptenmat. +% double - Convert a sptenmat to a sparse matrix. +% end - Last index of indexing expression for sptenmat. +% full - Convert a sptenmat to a (dense) tenmat. +% nnz - Return number of nonzeros in a sptenmat. +% norm - Frobenius norm of a sptenmat. +% size - Return size of sptenmat. +% sptenmat - Matricized sparse tensor stored as a sparse 2D array. +% subsasgn - Subscripted assignment for sptenmat. +% subsref - Subscripted reference for a sptenmat. +% tsize - Tensor size of sptenmat. +% uminus - Unary minus (-) for sptenmat. +% uplus - Unary plus (+) for sptenmat. diff --git a/external/tensor_toolbox_2.5/@sptenmat/aatx.m b/external/tensor_toolbox_2.5/@sptenmat/aatx.m new file mode 100755 index 0000000..fd38add --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/aatx.m @@ -0,0 +1,39 @@ +function z = aatx(a,x) +%AATX Implicitly compute A * A' * x for sptenmat. +% +% Z = AATX(A,X) takes a sptenmat object A and computes A * A' * +% X. This is done without converting A to a standard MATLAB sparse +% matrix. +% +% This function is likely most useful as an argument to a routine +% such as EIGS. +% +% See also SPTENMAT, SPTENSOR/EIGS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +subs = a.subs; +s1 = subs(:,1); +s2 = subs(:,2); +m = size(a,1); +n = size(a,2); +vals = a.vals; + +v1 = x(s1); +v1 = vals .* v1; +y = accumarray(s2, v1, [n 1]); + +v2 = y(s2); +v2 = vals .* v2; +z = accumarray(s1, v2, [m 1]); + diff --git a/external/tensor_toolbox_2.5/@sptenmat/disp.m b/external/tensor_toolbox_2.5/@sptenmat/disp.m new file mode 100755 index 0000000..bba787a --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/disp.m @@ -0,0 +1,66 @@ +function disp(a,name) +%DISP Command window display of a sptenmat. +% +% DISP(T) displays the tensor without printing its name. +% +% DISP(T,NAME) displays the tensor with the given name. +% +% See also SPTENMAT/DISPLAY. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~exist('name','var') + name = 'ans'; +end + +% Extract the number of nonzeros and number of dimensions +nz = size(a.vals,1); + +% Print an intro sentence giving the name and the size +if (nz == 0) + fprintf('%s is an all-zero sptenmat from an sptensor of size %s\n',... + name, tt_size2str(a.tsize)); +else + fprintf('%s is a sptenmat from an sptensor of size %s with %d nonzeros\n',... + name, tt_size2str(a.tsize), nz); +end + +fprintf(1,'\t%s.rindices = %s (modes of tensor corresponding to rows)\n',... + name,['[ ' num2str(a.rdims) ' ]'] ); +fprintf(1,'\t%s.cindices = %s (modes of tensor corresponding to columns)\n',... + name,['[ ' num2str(a.cdims) ' ]'] ); + + +% Stop insane printouts +if (nz > 1000) + r = input('Are you sure you want to print all nonzeros? (Y/N) ','s'); + if upper(r) ~= 'Y', return, end; +end + +% Return now if there are no nonzeros +if (nz == 0) + return; +end + +% Pre-allocate memory for the output +output = cell(nz,1); +spc = floor(log10(max(a.subs)))+1; +fmt = ['\t(%' num2str(spc(1)) 'd,%' num2str(spc(2)) 'd)\t%g']; + +for i = 1:nz + output{i} = sprintf(fmt, a.subs(i,:), a.vals(i)); +end +fprintf('%s\n',output{:}); + + + diff --git a/external/tensor_toolbox_2.5/@sptenmat/display.m b/external/tensor_toolbox_2.5/@sptenmat/display.m new file mode 100755 index 0000000..4a7fdcf --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/display.m @@ -0,0 +1,20 @@ +function display(t) +%DISPLAY Command window display of a sptenmat. +% +% DISPLAY(T) displays the tensor with its name. +% +% See also SPTENMAT/DISP. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +disp(t,inputname(1)); diff --git a/external/tensor_toolbox_2.5/@sptenmat/double.m b/external/tensor_toolbox_2.5/@sptenmat/double.m new file mode 100755 index 0000000..9612ee3 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/double.m @@ -0,0 +1,26 @@ +function A = double(T) +%DOUBLE Convert a sptenmat to a sparse matrix. +% +% A = double(T) converts T stored as a SPTENMAT to a sparse matrix. +% +% See also SPTENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +m = prod(T.tsize(T.rdims)); +n = prod(T.tsize(T.cdims)); +if isempty(T.subs) + A = sparse(m,n); +else + A = sparse(T.subs(:,1), T.subs(:,2), T.vals, m, n); +end diff --git a/external/tensor_toolbox_2.5/@sptenmat/end.m b/external/tensor_toolbox_2.5/@sptenmat/end.m new file mode 100755 index 0000000..112adfb --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/end.m @@ -0,0 +1,24 @@ +function e = end(X,k,n) +%END Last index of indexing expression for sptenmat. +% +% The expression X(end,:) will call END(X,1,2) to determine +% the value of the first index. +% +% See also SPTENMAT, SPTENMAT/SUBSREF, END. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if n > 2 + error('Subscript out of range.'); +end +e = size(X,k); diff --git a/external/tensor_toolbox_2.5/@sptenmat/full.m b/external/tensor_toolbox_2.5/@sptenmat/full.m new file mode 100755 index 0000000..985b22b --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/full.m @@ -0,0 +1,30 @@ +function B = full(A) +%FULL Convert a sptenmat to a (dense) tenmat. +% +% B = FULL(A) converts a sptenmat A to a (dense) tenmat B. +% +% See also SPTENMAT, TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Extract the order and size of A +siz = size(A); + +% Create a dense zero tensor B that is the same size as A +B = tenmat(zeros([siz,1,1]), A.rdims, A.cdims, A.tsize); + +% Extract the linear indices of entries in A +idx = tt_sub2ind(siz,A.subs); + +% Copy the values of A into B using linear indices +B(idx) = A.vals; diff --git a/external/tensor_toolbox_2.5/@sptenmat/nnz.m b/external/tensor_toolbox_2.5/@sptenmat/nnz.m new file mode 100755 index 0000000..687ab7e --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/nnz.m @@ -0,0 +1,20 @@ +function n = nnz(a) +%NNZ Return number of nonzeros in a sptenmat. +% +% nnz(A) returns the number of nonzeros in A. +% +% See also SPTENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +n = length(a.vals); diff --git a/external/tensor_toolbox_2.5/@sptenmat/norm.m b/external/tensor_toolbox_2.5/@sptenmat/norm.m new file mode 100755 index 0000000..0cb1f14 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/norm.m @@ -0,0 +1,22 @@ +function nrm = norm(T) +%NORM Frobenius norm of a sptenmat. +% +% NORM(T) returns the Frobenius norm of a matricized sparse tensor. +% +% See also SPTENMAT, NORM. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +nrm = norm(T.vals); + +return; diff --git a/external/tensor_toolbox_2.5/@sptenmat/size.m b/external/tensor_toolbox_2.5/@sptenmat/size.m new file mode 100755 index 0000000..c4f4e78 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/size.m @@ -0,0 +1,33 @@ +function siz = size(a,idx) +%SIZE Return size of sptenmat. +% +% D = SIZE(T) returns the size of the tensor. +% +% I = size(T,DIM) returns the sizes of the dimensions specified by DIM. +% +% See also SPTENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(a.tsize) + siz = []; + return; +end + +m = prod(a.tsize(a.rdims)); +n = prod(a.tsize(a.cdims)); +siz = [m n]; + +if exist('idx','var') + siz = siz(idx); +end diff --git a/external/tensor_toolbox_2.5/@sptenmat/sptenmat.m b/external/tensor_toolbox_2.5/@sptenmat/sptenmat.m new file mode 100755 index 0000000..667934d --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/sptenmat.m @@ -0,0 +1,244 @@ +function a = sptenmat(varargin) +%SPTENMAT Matricized sparse tensor stored as a sparse 2D array. +% +% A = SPTENMAT(T, RDIMS) creates a sparse matrix representation of +% an sptensor T. The dimensions (or modes) specified in RDIMS map +% to the rows of the matrix, and the remaining dimensions (in +% ascending order) map to the columns. +% +% A = SPTENMAT(T, CDIMS, 't') does the same as above, but instead +% the column dimensions are specified, and the remaining dimensions +% (in ascending order) map to the rows. +% +% A = SPTENMAT(T, RDIMS, CDIMS) creates a sparse matrix +% representation of sptensor T. The dimensions specified in RDIMS +% map to the rows of the matrix, and the dimensions specified in +% CDIMS map to the columns, in the order given. +% +% A = SPTENMAT(T, RDIM, STR) creates the same matrix representation +% as above, except only one dimension in RDIM maps to the rows of +% the matrix, and the remaining dimensions span the columns in an +% order specified by the string argument STR as follows: +% +% 'fc' - Forward cyclic. Order the remaining dimensions in the +% columns by [RDIM+1:ndims(T), 1:RDIM-1]. This is the +% ordering defined by Kiers. +% +% 'bc' - Backward cyclic. Order the remaining dimensions in the +% columns by [RDIM-1:-1:1, ndims(T):-1:RDIM+1]. This is the +% ordering defined by De Lathauwer, De Moor, and Vandewalle. +% +% A = SPTENAMT(B,RDIMS,CDIMS,TSIZE) creates a sptenmat from a matrix B +% along with the mappings of the row (RDIMS) and column indices (CDIMS) +% and the size of the original tensor (TSIZE). +% +% A = SPTENMAT(SUBS, VALS, RDIMS, CDIMS, TSIZE) creates a sptenmat +% from a set of 2D subscripts (SUBS) and values (VALS) along with +% the mappings of the row (RDIMS) and column indices (CDIMS) and the +% size of the original tensor (TSIZE). +% +% A = SPTENMAT is the empty constructor. +% +% See also SPTENSOR, TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%---------- +% EMPTY CONSTRUCTOR +%---------- +if (nargin == 0) + a.tsize = []; + a.rdims = []; + a.cdims = []; + a.subs = []; + a.vals = []; + a = class(a, 'sptenmat'); + return; +end + +%---------- +% COPY CONSTRUCTOR +%---------- +if (nargin == 1) && isa(varargin{1},'sptenmat') + t = varargin{1}; + a.tsize = t.tsize; + a.rdims = t.rdims; + a.cdims = t.cdims; + a.subs = t.subs; + a.vals = t.vals; + a = class(a, 'sptenmat'); + return; +end + +%---------- +% CONVERT LIST OF SUBS/VALS +%---------- +if (nargin == 5) + + subs = varargin{1}; + vals = varargin{2}; + rdims = varargin{3}; + cdims = varargin{4}; + tsize = varargin{5}; + + % Error check + n = numel(tsize); + if ~isequal(1:n, sort([rdims cdims])) + error('Incorrect specification of dimensions'); + elseif ~isempty(subs) && prod(tsize(rdims)) < max(subs(:,1)) + error('Invalid row index'); + elseif ~isempty(subs) && prod(tsize(cdims)) < max(subs(:,2)) + error('Invalid column index'); + end + + % Sum any duplicates + if isempty(subs) + newsubs = []; + newvals = []; + else + % Identify only the unique indices + [newsubs,junk,loc] = unique(subs,'rows'); + + % Sum the corresponding values + newvals = accumarray(loc,vals,[size(newsubs,1) 1]); + end + + % Find the nonzero indices of the new values + nzidx = find(newvals); + newsubs = newsubs(nzidx,:); + newvals = newvals(nzidx); + + % Save class variables + a.tsize = tsize; + a.rdims = rdims; + a.cdims = cdims; + a.subs = newsubs; + a.vals = newvals; + a = class(a, 'sptenmat'); + return; + +end + +%---------- +% CONVERT SPARSE or DENSE MATLAB MATRIX +%---------- +if (nargin == 4) + + B = varargin{1}; + [i,j,vals] = find(B); + subs = [i j]; + rdims = varargin{2}; + cdims = varargin{3}; + tsize = varargin{4}; + + % Error check + n = numel(tsize); + if ~isequal(1:n, sort([rdims cdims])) + error('Incorrect specification of dimensions'); + elseif ~isempty(subs) && prod(tsize(rdims)) < max(subs(:,1)) + error('Invalid row index'); + elseif ~isempty(subs) && prod(tsize(cdims)) < max(subs(:,2)) + error('Invalid column index'); + end + + % Save class variables + a.tsize = tsize; + a.rdims = rdims; + a.cdims = cdims; + a.subs = subs; + a.vals = vals; + a = class(a, 'sptenmat'); + return; + +end + + +%---------- +% CONVERT SPTENSOR +%---------- + +if (nargin < 2) || (nargin > 3) + error('Incorrect number of arguments.'); +end + +% Save the size of T and the number of dimensions +T = varargin{1}; +tsize = size(T); +tsubs = T.subs; +tvals = T.vals; +n = ndims(T); + +% Figure out which dimensions get mapped where +if (nargin == 2) + rdims = varargin{2}; + cdims = setdiff(1:n, rdims); +elseif isa(varargin{3},'char') + switch varargin{3} + case 't' % Transpose + cdims = varargin{2}; + rdims = setdiff(1:n, cdims); + case 'fc' % Forward cyclic + rdims = varargin{2}; + if (numel(rdims) ~= 1) + error('Only one row dimension if third argument is ''fc''.'); + end + cdims = [rdims+1:n, 1:rdims-1]; + case 'bc' % Backward cyclic + rdims = varargin{2}; + if (numel(rdims) ~= 1) + error('Only one row dimension if third argument is ''bc''.'); + end + cdims = [rdims-1:-1:1, n:-1:rdims+1]; + otherwise + error('Unrecognized option'); + end +else + rdims = varargin{2}; + cdims = varargin{3}; +end + +% Error check +if ~isequal(1:n, sort([rdims cdims])) + error('Incorrect specification of dimensions'); +end + +% Extract the appropriate sizes +rsize = tsize(rdims); +csize = tsize(cdims); + +% Reshape by transforming the indices +if isempty(rsize) + ridx = ones(nnz(T),1); +elseif isempty(tsubs) + ridx = []; +else + ridx = tt_sub2ind(rsize,tsubs(:,rdims)); +end + +if isempty(csize) + cidx = ones(nnz(T),1); +elseif isempty(tsubs) + cidx = []; +else + cidx = tt_sub2ind(csize,tsubs(:,cdims)); +end + +% Save class variables +a.tsize = tsize; +a.rdims = rdims; +a.cdims = cdims; +a.subs = [ridx, cidx]; +a.vals = tvals; +a = class(a, 'sptenmat'); + + diff --git a/external/tensor_toolbox_2.5/@sptenmat/subsasgn.m b/external/tensor_toolbox_2.5/@sptenmat/subsasgn.m new file mode 100755 index 0000000..f5218ae --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/subsasgn.m @@ -0,0 +1,70 @@ +function t = subsasgn(t,s,b) +%SUBSASGN Subscripted assignment for sptenmat. +% +% Examples +% X = sptenmat(sptenrand([3 4 2],10),1); +% X(1:2,1:2) = ones(2,2); <-- Calls SUBSASGN +% +% See also SPTENMAT, SPTENMAT/SUBSREF. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%TODO: Make implementation efficient. It's not right now. +%TODO: Add error checking. + +switch s.type + case '()' + rsubs = s.subs{1}; + csubs = s.subs{2}; + + % If called with single element in rhs, then create a vector + if numel(b) == 1 + b = repmat(b, numel(rsubs) * numel(csubs), 1); + end + + % Initialize some variables for new entries in the matrix + newsubs = []; + newvals = []; + + k = 0; + + % Loop over the row and column indices, finding the + % appropriate row index for the (i,j) subscript + for j = 1:length(csubs) + indxc = find(t.subs(:,2) == csubs(j)); + for i = 1:length(rsubs) + indxr = find(t.subs(indxc,1) == rsubs(i)); + indx = indxc(indxr); + + k = k + 1; % increment counter into b + if isempty(indx) + newsubs = [newsubs; rsubs(i) csubs(j)]; + newvals = [newvals; b(k)]; + else + %t.subs(indx,:); + t.vals(indx) = b(k); + end + end + end + + % If there are new values to append, then add them on and sort + if ~isempty(newvals) + t.subs = [t.subs; newsubs]; + t.vals = [t.vals; newvals]; + [t.subs,indx] = sortrows(t.subs); + t.vals = t.vals(indx); + end + + otherwise + error('Invalid assignment for sptenmat.') +end diff --git a/external/tensor_toolbox_2.5/@sptenmat/subsref.m b/external/tensor_toolbox_2.5/@sptenmat/subsref.m new file mode 100755 index 0000000..f03d226 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/subsref.m @@ -0,0 +1,43 @@ +function a = subsref(t,s) +%SUBSREF Subscripted reference for a sptenmat. +% +% Examples +% A.subs <-- returns the nonzero values as an array +% A.vals <-- returns the corresponding 2D subscripts +% A.tsize <-- returns the size original tensor +% A.rdims <-- tensor dimensions that were mapped to rows +% A.cdims <-- tensor dimensions that were mapped to columns +% +% See also SPTENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +switch s(1).type + case '.' + switch s(1).subs + case 'vals' + a = tt_subsubsref(t.vals,s); + case 'tsize' + a = t.tsize; + case 'rdims' + a = t.rdims; + case 'cdims' + a = t.cdims; + case 'subs' + a = tt_subsubsref(t.subs,s); + otherwise + error(['No such field: ', s.subs]); + end + otherwise + error('Invalid subsref into tenmat.') +end diff --git a/external/tensor_toolbox_2.5/@sptenmat/tsize.m b/external/tensor_toolbox_2.5/@sptenmat/tsize.m new file mode 100755 index 0000000..beae1d2 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/tsize.m @@ -0,0 +1,36 @@ +function sz = tsize(a,idx) +%TSIZE Tensor size of sptenmat. +% +% D = TSIZE(X) returns the size of the tensor being stored as a +% matrix. +% +% M = TSIZE(X,DIM) returns the length of the dimension(s) specified +% by DIM. For example, SIZE(X,1) returns the size of the first +% dimension of the tensor. +% +% See also SPTENMAT, SPTENMAT/SIZE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(a.tsize) + sz = []; + return; +end + +if exist('idx', 'var') + sz = a.tsize(idx); +else + sz = a.tsize; +end + +return; diff --git a/external/tensor_toolbox_2.5/@sptenmat/uminus.m b/external/tensor_toolbox_2.5/@sptenmat/uminus.m new file mode 100755 index 0000000..89ae5ec --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/uminus.m @@ -0,0 +1,18 @@ +function t = uminus(t) +%UMINUS Unary minus (-) for sptenmat. +% +% See also SPTENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +t.vals = -t.vals; diff --git a/external/tensor_toolbox_2.5/@sptenmat/uplus.m b/external/tensor_toolbox_2.5/@sptenmat/uplus.m new file mode 100755 index 0000000..c0e1d6d --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptenmat/uplus.m @@ -0,0 +1,19 @@ +function t = uplus(t) +%UPLUS Unary plus (+) for sptenmat. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% This function does nothing! + diff --git a/external/tensor_toolbox_2.5/@sptensor/Contents.m b/external/tensor_toolbox_2.5/@sptensor/Contents.m new file mode 100755 index 0000000..f1ae485 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/Contents.m @@ -0,0 +1,55 @@ +% @SPTENSOR +% +% Files +% and - Logical AND (&) for sptensors. +% collapse - Collapse sparse tensor along specified dimensions. +% contract - Contract sparse tensor along two dimensions (array trace). +% ctranspose - is not defined for sparse tensors. +% disp - Command window display of a sparse tensor. +% display - Command window display of a sparse tensor. +% divide - Divide an SPTENSOR by a nonnegative KTENSOR. +% double - Converts a sparse tensor to a dense multidimensional array. +% elemfun - Manipulate the nonzero elements of a sparse tensor. +% end - Last index of indexing expression for sparse tensor. +% eq - Equal (==) for sptensors. +% find - Find subscripts of nonzero elements in a sparse tensor. +% full - Convert a sparse tensor to a (dense) tensor. +% ge - Greater than or equal for sptensors. +% gt - Greater than for sptensors. +% innerprod - Efficient inner product with a sparse tensor. +% isequal - for sptensors. +% ldivide - Array right division for sparse tensors. +% le - Less than or equal for sptensors. +% lt - Less than for sptensors. +% minus - Binary subtraction for sparse tensors. +% mldivide - Slash left division for sparse tensors. +% mrdivide - Slash right division for sparse tensors. +% mtimes - sptensor-scalar multiplication. +% mttkrp - Matricized tensor times Khatri-Rao product for sparse tensor. +% ndims - Number of dimensions of a sparse tensor. +% ne - Not equal (~=) for sptensors. +% nnz - Number of nonzeros in sparse tensor. +% norm - Frobenius norm of a sparse tensor. +% not - Logical NOT (~) for sptensors. +% nvecs - Compute the leading mode-n vectors for a sparse tensor. +% ones - Replace nonzero elements of sparse tensor with ones. +% or - Logical OR (|) for sptensors. +% permute - Rearrange the dimensions of a sparse tensor. +% plus - Binary addition for sparse tensors. +% rdivide - Array right division for sparse tensors. +% reshape - Reshape sparse tensor. +% scale - Scale along specified dimensions for sparse tensors. +% size - Sparse tensor dimensions. +% spmatrix - Converts a two-way sparse tensor to sparse matrix. +% sptensor - Create a sparse tensor. +% squeeze - Remove singleton dimensions from a sparse tensor. +% subsasgn - Subscripted assignment for sparse tensor. +% subsref - Subscripted reference for a sparse tensor. +% times - Array multiplication for sparse tensors. +% transpose - is not defined on sparse tensors. +% ttm - Sparse tensor times matrix. +% ttt - Sparse tensor times sparse tensor. +% ttv - Sparse tensor times vector. +% uminus - Unary minus (-) for sptensor. +% uplus - Unary plus (+) for sptensor. +% xor - Logical XOR for sptensors. diff --git a/external/tensor_toolbox_2.5/@sptensor/and.m b/external/tensor_toolbox_2.5/@sptensor/and.m new file mode 100755 index 0000000..51502a7 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/and.m @@ -0,0 +1,58 @@ +function C = and(A,B) +%AND Logical AND (&) for sptensors. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a & 5 is sparse. +% The result of a & 0 is sparse. +% The result of a & full(a) is sparse. + +%% Case 1: One argument is a scalar +if isscalar(B) + if B == 0 + C = sptensor([],[],size(A)); + else + C = sptensor(A.subs,true,size(A)); + end + return; +end + +% Call back with the arguments reversed. +if isscalar(A) + C = and(B,A); + return; +end + +%% Case 2: Both x and y are tensors of some sort +% Check that the sizes match +if ~isequal(size(A),size(B)) + error('Must be tensors of the same size'); +end + +if isa(A,'sptensor') && isa(B,'sptensor') + C = sptensor([A.subs; B.subs], [A.vals; B.vals], size(A), ... + @(x) length(x) == 2); + return; +end + +if isa(B,'tensor') + BB = sptensor(A.subs,B(A.subs),size(A)); + C = and(A,BB); + return; +end + +%% Otherwise +error('The arguments must be two sptensors or an sptensor and a scalar.'); diff --git a/external/tensor_toolbox_2.5/@sptensor/collapse.m b/external/tensor_toolbox_2.5/@sptensor/collapse.m new file mode 100755 index 0000000..d4e1be3 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/collapse.m @@ -0,0 +1,71 @@ +function s = collapse(t,dims,fun) +%COLLAPSE Collapse sparse tensor along specified dimensions. +% +% S = COLLAPSE(T,DIMS) sums the entries of T along all dimensions +% specified in DIMS. If DIMS is negative, then T is summed across +% all dimensions *not* specified by -DIMS. +% +% S = COLLAPSE(T) is shorthand for S = COLLAPSE(T,1:ndims(T)). +% +% S = COLLAPSE(T,DIMS,FUN) accumulates the entries of T using the +% accumulation function @FUN. +% +% Examples +% subs = [1 1 1; 1 1 3; 2 2 4; 4 4 4] +% vals = [10.5; 1.5; 2.5; 3.5] +% X = sptensor(subs,vals,[4 4 4]); +% Y = collapse(X,[2 3]) %<-- sum of entries in each mode-1 slice +% Y = collapse(ones(X),[1 2]) %<-- nnz in each mode-3 slide +% Y = collapse(ones(X),[1 2],@max) %<-- 1 if mode-3 has any entry +% Y = collapse(ones(X),-3,@max); %<-- equivalent +% +% See also SPTENSOR, SPTENSOR/SCALE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~exist('fun', 'var') + fun = @sum; +end + +if ~exist('dims', 'var') + dims = 1:ndims(t); +end + +dims = tt_dimscheck(dims,ndims(t)); +remdims = setdiff(1:ndims(t),dims); + +% Check for the case where we accumulate over *all* dimensions +if isempty(remdims) + s = fun(t.vals); + return; +end + +% Calculate the size of the result +newsiz = size(t,remdims); + +% Check for the case where the result is just a dense vector +if numel(remdims) == 1 + if ~isempty(t.subs) + s = accumarray(t.subs(:,remdims), t.vals, [newsiz 1], fun); + else + s = zeros(newsiz,1); + end + return; +end + +% Create the result +if ~isempty(t.subs) + s = sptensor(t.subs(:,remdims), t.vals, newsiz, fun); +else + s = sptensor([],[],newsiz); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/contract.m b/external/tensor_toolbox_2.5/@sptensor/contract.m new file mode 100755 index 0000000..5a9497d --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/contract.m @@ -0,0 +1,60 @@ +function y = contract(x,i,j) +%CONTRACT Contract sparse tensor along two dimensions (array trace). +% +% Y = CONTRACT(X,I,J) contracts the entries of X along dimensions I +% and J. Contraction is a generalization of matrix trace. In other +% words, the trace is performed along the two-dimensional slices +% defined by dimensions I and J. It is possible to implement tensor +% multiplication as an outer product followed by a contraction. +% +% Examples +% X = sptenrand([4 3 2],10); Y = sptenrand([3 2 4],10); +% Z1 = ttt(X,Y,1,3); %<-- Normal tensor multiplication +% Z2 = contract(ttt(X,Y),1,6); %<-- Outer product + contract +% norm(Z1-Z2) %<-- Should be zero +% +% See also SPTENSOR, SPTENSOR/TTT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Error checking +if x.size(i) ~= x.size(j) + error('Must contract along equally sized dimensions'); +end + +% Error checking +if i == j + error('Must contract along two different dimensions'); +end + +% Easy case - returns a scalar +if ndims(x) == 2 + tfidx = (x.subs(:,1) == x.subs(:,2)); % find diagonal entries + y = sum(x.vals(tfidx)); + return; +end + +% Remaining dimensions after contract +remdims = setdiff(1:ndims(x),[i j]); + +% Find index of values on diagonal +indx = find(x.subs(:,i) == x.subs(:,j)); + +% Let the constructor sum up the entries +y = sptensor(x.subs(indx,remdims),x.vals(indx),x.size(remdims)); + +% Check if result should be dense +if nnz(y) > 0.5 * prod(y.size) + % Final result is a *dense* tensor + y = tensor(y); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/ctranspose.m b/external/tensor_toolbox_2.5/@sptensor/ctranspose.m new file mode 100755 index 0000000..689dd0e --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/ctranspose.m @@ -0,0 +1,18 @@ +function ctranspose(x) +%CTRANSPOSE is not defined for sparse tensors. +% +% See also SPTENSOR/PERMUTE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +error('Transpose on sparse tensor is not defined'); diff --git a/external/tensor_toolbox_2.5/@sptensor/disp.m b/external/tensor_toolbox_2.5/@sptensor/disp.m new file mode 100755 index 0000000..ce714c9 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/disp.m @@ -0,0 +1,85 @@ +function disp(X,name) +%DISP Command window display of a sparse tensor. +% +% DISP(X) displays the tensor without printing its name. +% +% DISP(X,NAME) displays the tensor with the given name. +% +% See also SPTENSOR, SPTENSOR/DISPLAY. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Extract the number of nonzeros and number of dimensions +nz = nnz(X); + +if ~exist('name','var') + name = 'ans'; +end + +if (nz == 0) + fprintf('%s is an all-zero sparse tensor of size %s\n',... + name, tt_size2str(X.size)); + return; +else + fprintf('%s is a sparse tensor of size %s with %d nonzeros\n',... + name, tt_size2str(X.size), nz); +end + +% Stop insane printouts +if (nz > 10000) + r = input('Are you sure you want to print all nonzeros? (Y/N) ','s'); + if upper(r) ~= 'Y', return, end; +end + +% preallocate +output = cell(nz,1); +%% +spc = floor(log10(max(double(X.subs),[],1)))+1; +if numel(spc) == 1 + fmt = ['\t(%' num2str(spc(1)) 'd)%s']; +else + fmt = ['\t(%' num2str(spc(1)) 'd,']; + for i = 2:numel(spc)-1 + fmt = [fmt '%' num2str(spc(i)) 'd,']; + end + fmt = [fmt '%' num2str(spc(end)) 'd)%s']; +end +%% +% Get values out so that they look nice +savefmt = get(0,'FormatSpacing'); +format compact +S = evalc('disp(X.vals)'); +set(0,'FormatSpacing',savefmt) +S = textscan(S,'%s','delimiter','\n','whitespace',''); +S = S{1}; +if ~isempty(strfind(S{1},'*')) + fprintf('%s\n',S{1}); + S = S(2:end); +end +%% +for i = 1:nz + output{i} = sprintf(fmt,X.subs(i,:),S{i}); +end +fprintf('%s\n',output{:}); + +% function y = fmt(s,v) +% % nested function has access to n from disp function workspace +% if n > 1 +% y = [sprintf('\t(') sprintf('%d,',s(1:n-1))... +% sprintf('%d) ',s(n)) sprintf('\t%g',v)]; +% else +% y = sprintf('\t(%d) \t%f',s,v); +% end +% end + +end diff --git a/external/tensor_toolbox_2.5/@sptensor/display.m b/external/tensor_toolbox_2.5/@sptensor/display.m new file mode 100755 index 0000000..05410ab --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/display.m @@ -0,0 +1,20 @@ +function display(t) +%DISPLAY Command window display of a sparse tensor. +% +% DISPLAY(T) displays the tensor with its name. +% +% See also SPTENSOR, SPTENSOR/DISP. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +disp(t,inputname(1)); diff --git a/external/tensor_toolbox_2.5/@sptensor/divide.m b/external/tensor_toolbox_2.5/@sptensor/divide.m new file mode 100755 index 0000000..1e3a540 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/divide.m @@ -0,0 +1,37 @@ +function Y = divide(X,K,epsilon) +%DIVIDE Divide an SPTENSOR by a nonnegative KTENSOR. +% +% Y = DIVIDE(X,K,EPSILON) divides the sparse tensor X by the +% nonnegative ktensor K. Avoids divide-by-zero errors by dividing +% by MIN(EPSILON,K-VALUE) at each nonzero of X. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +% Assumes K is a nonnegative ktensor + +Y = X; + +subs = Y.subs; +vals = zeros(size(Y.vals)); +R = numel(K.lambda); +N = ndims(Y); +for r = 1:R + tvals = ones(size(vals)) * K.lambda(r); + for n = 1:N + v = K{n}(:,r); + tvals = tvals .* v(subs(:,n)); + end + vals = vals + tvals; +end +Y.vals = Y.vals ./ max(epsilon, vals); + +return; diff --git a/external/tensor_toolbox_2.5/@sptensor/double.m b/external/tensor_toolbox_2.5/@sptensor/double.m new file mode 100755 index 0000000..ca77993 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/double.m @@ -0,0 +1,21 @@ +function a = double(s) +%DOUBLE Converts a sparse tensor to a dense multidimensional array. +% +% See also SPTENSOR, SPTENSOR/FULL. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +a = zeros([size(s) 1 1]); +if nnz(s) > 0 + a(tt_sub2ind(size(s),s.subs)) = s.vals; +end diff --git a/external/tensor_toolbox_2.5/@sptensor/elemfun.m b/external/tensor_toolbox_2.5/@sptensor/elemfun.m new file mode 100755 index 0000000..0c32054 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/elemfun.m @@ -0,0 +1,41 @@ +function a = elemfun(a,fun) +%ELEMFUN Manipulate the nonzero elements of a sparse tensor. +% +% X = ELEMFUN(X,@FUN) modifies the elements of X according to the +% function @FUN which should take and array and output an equally +% sized array. +% +% Examples +% X = sptenrand([10,10,10],10); +% X = elemfun(X,@sqrt) %<-- square root of every entry +% X = elemfun(X, @(x) x+1) %<-- increase every entry by 1 +% X = elemfun(X, @(x) x ~= 0) %<-- change every nonzero to be 1 +% +% See also SPTENSOR, SPFUN. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +if ~isa(a,'sptensor') + error('First argument must be a sparse tensor.'); +end + +a.vals = fun(a.vals); +idx = find(a.vals); +if isempty(idx) + a.vals = []; + a.subs = []; +else + a.vals = a.vals(idx); + a.subs = a.subs(idx,:); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/end.m b/external/tensor_toolbox_2.5/@sptensor/end.m new file mode 100755 index 0000000..56281cf --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/end.m @@ -0,0 +1,24 @@ +function e = end(X,k,n) +%END Last index of indexing expression for sparse tensor. +% +% The expression X(end,:,:) will call END(X,1,3) to determine +% the value of the first index. +% +% See also SPTENSOR, SPTENSOR/SUBSREF, END. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if n > ndims(X) + error('Subscript out of range.'); +end +e = X.size(k); diff --git a/external/tensor_toolbox_2.5/@sptensor/eq.m b/external/tensor_toolbox_2.5/@sptensor/eq.m new file mode 100755 index 0000000..936bcdd --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/eq.m @@ -0,0 +1,88 @@ +function z = eq(x,y) +%EQ Equal (==) for sptensors. +% +% A == B compares the elements of A and B for equality. The arguments can +% be a pair of sptensors, an sptensor and a tensor, or an sptensor and a +% scalar. Regardless, the result is always returned as a sparse tensor. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a == 5 is sparse. +% The result of a == 0 is sparse. +% The result of a == full(a) is sparse. + +%% Case 1: One argument is a scalar +if isscalar(y) + if y == 0 + z = ~x; + else + idx = (x.vals == y); + z = sptensor(x.subs(idx,:),true,size(x)); + end + return; +end + +% Call back with the arguments reversed. +if isscalar(x) + z = eq(y,x); + return; +end + +%% Case 2: Both x and y are tensors of some sort +% Check that the sizes match +if ~isequal(x.size,y.size) + error('Size mismatch'); +end + +% Case 2a: Two sparse tensors +if isa(x,'sptensor') && isa(y,'sptensor') + + % Find where their zeros intersect + xzerosubs = setdiff(allsubs(x),x.subs,'rows'); + yzerosubs = setdiff(allsubs(y),y.subs,'rows'); + zzerosubs = intersect(xzerosubs,yzerosubs,'rows'); + + % find where their nonzeros intersect + [nzsubs,ix,iy] = intersect(x.subs,y.subs,'rows'); + znzsubs = nzsubs(x.vals(ix) == y.vals(iy),:); + + % Build z + z = sptensor([zzerosubs;znzsubs],true,x.size); + + return; + +end + +% Case 2b: One dense tensor +if isa(y,'tensor') + + % Find where their zeros intersect + yzerosubs = find(y == 0); + zzerosubs = yzerosubs(extract(x,yzerosubs) == 0,:); + + % Find where their nonzeros intersect + yvals = y(x.subs); + znzsubs = x.subs(yvals == x.vals,:); + + % Build z + z = sptensor([zzerosubs;znzsubs],true,x.size); + + return; + +end + +%% Otherwise +error('The arguments must be two sptensors or an sptensor and a scalar.'); diff --git a/external/tensor_toolbox_2.5/@sptensor/find.m b/external/tensor_toolbox_2.5/@sptensor/find.m new file mode 100755 index 0000000..2a23ab8 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/find.m @@ -0,0 +1,27 @@ +function [subs,vals] = find(t) +%FIND Find subscripts of nonzero elements in a sparse tensor. +% +% [SUBS,VALS] = FIND(T) returns the subscripts and corresponding +% values of the nonzero elements of T. +% +% Note that unlike the standard MATLAB find function for an array, +% find does not return linear indices. Instead, it returns an M x N +% array where M is the number of nonzero values and N = ndims(T). +% Thus, I(k,:) specifies the subscript of value V(k). +% +% See also SPTENSOR, FIND. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +subs = t.subs; +vals = t.vals; diff --git a/external/tensor_toolbox_2.5/@sptensor/full.m b/external/tensor_toolbox_2.5/@sptensor/full.m new file mode 100755 index 0000000..b7539be --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/full.m @@ -0,0 +1,35 @@ +function B = full(A) +%FULL Convert a sparse tensor to a (dense) tensor. +% +% B = FULL(A) converts a sptensor A to a (dense) tensor B. +% +% See also SPTENSOR, TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Extract the order and size of A +siz = size(A); + +% Create a dense zero tensor B that is the same size as A +B = tensor(zeros([siz,1,1]),siz); + +if isempty(A.subs) + return; +end + +% Extract the linear indices of entries in A +idx = tt_sub2ind(siz,A.subs); + +% Copy the values of A into B using linear indices +B(idx) = A.vals; + diff --git a/external/tensor_toolbox_2.5/@sptensor/ge.m b/external/tensor_toolbox_2.5/@sptensor/ge.m new file mode 100755 index 0000000..ab2aa49 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/ge.m @@ -0,0 +1,71 @@ +function z = ge(x,y) +%GE Greater than or equal for sptensors. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a >= 5 is sparse. +% The result of a >= 0 is sparse. +% The result of a >= full(a) is sparse. + +%% Case 1: One argument is a scalar +if isscalar(y) + subs1 = x.subs((x.vals >= y),:); + if y <= 0 + subs2 = setdiff(allsubs(x),x.subs,'rows'); + else + subs2 = []; + end + z = sptensor([subs1;subs2],true,size(x)); + return; +end + +% Call back with the arguments reversed. +if isscalar(x) + z = le(y,x); + return; +end + +%% Case 2: Both x and y are tensors of some sort +% Check that the sizes match +if ~isequal(x.size,y.size) + error('Size mismatch'); +end + +% Case 2a: Two sparse tensors +if isa(x,'sptensor') && isa(y,'sptensor') + z = le(y,x); + return; +end + +% Case 2b: One dense tensor +if isa(y,'tensor') + + % x zero + subs1 = find(y <= 0); + subs1 = setdiff(subs1,x.subs,'rows'); + + % x nonzero + subs2 = x.subs(x.vals >= y(x.subs,'extract'),:); + + % assemble + z = sptensor([subs1;subs2],true,size(x)); + + return; + +end + +%% Otherwise +error('The arguments must be two sptensors or an sptensor and a scalar.'); diff --git a/external/tensor_toolbox_2.5/@sptensor/gt.m b/external/tensor_toolbox_2.5/@sptensor/gt.m new file mode 100755 index 0000000..5ee87bd --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/gt.m @@ -0,0 +1,74 @@ +function z = gt(x,y) +%GT Greater than for sptensors. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a > 5 is sparse. +% The result of a > 0 is sparse. +% The result of a > full(a) is sparse. +% The result of a > zeros(a) is sparse. + +%% Case 1: One argument is a scalar +if isscalar(y) + subs1 = x.subs((x.vals > y),:); + if y < 0 + subs2 = setdiff(allsubs(x),x.subs,'rows'); + else + subs2 = []; + end + z = sptensor([subs1;subs2],true,size(x)); + return; +end + +% Call back with the arguments reversed. +if isscalar(x) + z = lt(y,x); + return; +end + +%% Case 2: Both x and y are tensors of some sort +% Check that the sizes match +if ~isequal(x.size,y.size) + error('Size mismatch'); +end + +% Case 2a: Two sparse tensors +if isa(x,'sptensor') && isa(y,'sptensor') + z = lt(y,x); + return; +end + +% Case 2b: One dense tensor +if isa(y,'tensor') + + % x zero and y < 0 + subs1 = find(y < 0); + if ~isempty(subs1) + subs1 = setdiff(subs1,x.subs,'rows'); + end + + % x and y nonzero + subs2 = x.subs(x.vals > y(x.subs,'extract'),:); + + % assemble + z = sptensor([subs1;subs2],true,size(x)); + + return; + +end + +%% Otherwise +error('The arguments must be two sptensors or an sptensor and a scalar.'); diff --git a/external/tensor_toolbox_2.5/@sptensor/innerprod.m b/external/tensor_toolbox_2.5/@sptensor/innerprod.m new file mode 100755 index 0000000..d9c6344 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/innerprod.m @@ -0,0 +1,59 @@ +function res = innerprod(X,Y) +%INNERPROD Efficient inner product with a sparse tensor. +% +% R = INNERPROD(X,Y) efficiently computes the inner product between +% two tensors X and Y. If Y is a tensor or sptensor, the inner +% product is computed directly and the computational complexity is +% O(min(nnz(X),nnz(Y))). If Y is a ktensor or a ttensor, the +% inner product method for that type of tensor is called. +% +% See also SPTENSOR, KTENSOR/INNERPROD, TTENSOR/INNERPROD. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% X is a sptensor +switch class(Y) + + case {'sptensor'} + if ~isequal(size(X),size(Y)) + error('X and Y must be the same size.'); + end + if nnz(X) < nnz(Y); + [SX,VX] = find(X); + VY = extract(Y,SX); %<-----VY = Y(SX); + else + [SY,VY] = find(Y); + VX = extract(X,SY); %<-----VX = X(SY); + end + res = VY'*VX; + return; + + case {'tensor'} + if ~isequal(size(X),size(Y)) + error('X and Y must be the same size.'); + end + [SX,VX] = find(X); + VY = Y(SX,'extract'); + res = VY'*VX; + return; + + case {'ktensor','ttensor'} + % Reverse arguments to call ktensor/ttensor implementation + res = innerprod(Y,X); + return; + + otherwise + error(['Inner product not available for class ' class(Y)]); + +end + diff --git a/external/tensor_toolbox_2.5/@sptensor/isequal.m b/external/tensor_toolbox_2.5/@sptensor/isequal.m new file mode 100755 index 0000000..c170861 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/isequal.m @@ -0,0 +1,32 @@ +function z = isequal(x,y) +%ISEQUAL for sptensors. +% +% ISEQUAL(A,B) compares the sparse tensors A and B for equality. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of isequal(a,full(a)) is true! + +%% +if ~isequal(x.size,y.size) + z = false; +elseif isa(x,'sptensor') && isa(y,'sptensor') + z = (nnz(x-y) == 0); +elseif isa(y,'tensor') + z = isequal(full(x),y); +else + z = false; +end diff --git a/external/tensor_toolbox_2.5/@sptensor/ldivide.m b/external/tensor_toolbox_2.5/@sptensor/ldivide.m new file mode 100755 index 0000000..f8e4109 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/ldivide.m @@ -0,0 +1,21 @@ +function C = ldivide(A,B) +%LDIVIDE Array right division for sparse tensors. +% +% LDIVIDE(A,B) is called for the syntax 'A .\ B' when A or B is a sparse +% tensor. A and B must have the same size, unless one is a scalar. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +C = rdivide(B,A); diff --git a/external/tensor_toolbox_2.5/@sptensor/le.m b/external/tensor_toolbox_2.5/@sptensor/le.m new file mode 100755 index 0000000..ec984ad --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/le.m @@ -0,0 +1,91 @@ +function z = le(x,y) +%LE Less than or equal for sptensors. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a <= 5 is sparse. +% The result of a <= 0 is sparse. +% The result of a <= full(a) is sparse. + +%% Case 1: One argument is a scalar +if isscalar(y) + subs1 = x.subs((x.vals <= y),:); + if y >= 0 + subs2 = setdiff(allsubs(x),x.subs,'rows'); + else + subs2 = []; + end + z = sptensor([subs1;subs2],true,size(x)); + return; +end + +% Call back with the arguments reversed. +if isscalar(x) + z = ge(y,x); + return; +end + +%% Case 2: Both x and y are tensors of some sort +% Check that the sizes match +if ~isequal(x.size,y.size) + error('Size mismatch'); +end + +% Case 2a: Two sparse tensors +if isa(x,'sptensor') && isa(y,'sptensor') + + % x not zero, y zero + subs1 = setdiff(x.subs,y.subs,'rows'); + subs1 = subs1(extract(x,subs1) < 0, :); + + % x zero, y not zero + subs2 = setdiff(y.subs,x.subs,'rows'); + subs2 = subs2(extract(y,subs2) > 0, :); + + % x and y not zero + subs3 = intersect(x.subs,y.subs,'rows'); + subs3 = subs3(extract(x,subs3) <= extract(y,subs3),:); + + % x and y zero + xzerosubs = setdiff(allsubs(x),x.subs,'rows'); + yzerosubs = setdiff(allsubs(y),y.subs,'rows'); + subs4 = intersect(xzerosubs,yzerosubs,'rows'); + + % assemble + z = sptensor([subs1;subs2;subs3;subs4],true,size(x)); + return; + +end + +% Case 2b: One dense tensor +if isa(y,'tensor') + + % x zero + subs1 = find(y >= 0); + subs1 = setdiff(subs1,x.subs,'rows'); + + % x nonzero + subs2 = x.subs(x.vals <= y(x.subs,'extract'),:); + + % assemble + z = sptensor([subs1;subs2],true,size(x)); + + return; + +end + +%% Otherwise +error('The arguments must be two sptensors or an sptensor and a scalar.'); diff --git a/external/tensor_toolbox_2.5/@sptensor/lt.m b/external/tensor_toolbox_2.5/@sptensor/lt.m new file mode 100755 index 0000000..75b41b5 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/lt.m @@ -0,0 +1,88 @@ +function z = lt(x,y) +%LT Less than for sptensors. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a < 5 is sparse. +% The result of a < 0 is sparse. +% The result of a < full(a) is sparse. + +%% Case 1: One argument is a scalar +if isscalar(y) + subs1 = x.subs((x.vals < y),:); + if y > 0 + subs2 = setdiff(allsubs(x),x.subs,'rows'); + else + subs2 = []; + end + z = sptensor([subs1;subs2],true,size(x)); + return; +end + +% Call back with the arguments reversed. +if isscalar(x) + z = gt(y,x); + return; +end + +%% Case 2: Both x and y are tensors or some sort +% Check that the sizes match +if ~isequal(x.size,y.size) + error('Size mismatch'); +end + +% Case 2a: Two sparse tensors +if isa(x,'sptensor') && isa(y,'sptensor') + + % x not zero, y zero + subs1 = setdiff(x.subs,y.subs,'rows'); + subs1 = subs1(extract(x,subs1) < 0, :); + + % x zero, y not zero + subs2 = setdiff(y.subs,x.subs,'rows'); + subs2 = subs2(extract(y,subs2) > 0, :); + + % x and y not zero + subs3 = intersect(x.subs,y.subs,'rows'); + subs3 = subs3(extract(x,subs3) < extract(y,subs3),:); + + % assemble + z = sptensor([subs1;subs2;subs3],true,size(x)); + return; + +end + +% Case 2b: y is a dense tensor +if isa(y,'tensor') + + % x zero and y > 0 + subs1 = find(y > 0); + if ~isemtpy(subs1) + subs1 = setdiff(subs1,x.subs,'rows'); + end + + % x and y nonzero + subs2 = x.subs(x.vals < y(x.subs,'extract'),:); + + % assemble + z = sptensor([subs1;subs2],true,size(x)); + + return; + +end + +%% Otherwise +error('The arguments must be two sptensors or an sptensor and a scalar.'); diff --git a/external/tensor_toolbox_2.5/@sptensor/minus.m b/external/tensor_toolbox_2.5/@sptensor/minus.m new file mode 100755 index 0000000..fd6140b --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/minus.m @@ -0,0 +1,56 @@ +function C = minus(A,B) +%MINUS Binary subtraction for sparse tensors. +% +% MINUS(A,B) is called for the syntax 'A - B' when A or B is a sparse +% tensor. A and B must have the same size, unless one is a scalar. A +% scalar can be subtracted from a sparse tensor of any size. +% +% Examples +% A = sptenrand([4 3 2],5); B = sptenrand([4 3 2],3); +% A - B %<-- sparse +% A - 5 %<-- dense +% A - 0 %<-- dense +% A - full(A) %<-- dense +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a - 5 is dense! +% The result of a - 0 is dense! +% The result of a - full(a) is dense! +% The result of a - b (two sparse matrices) is sparse. + +%% Case 1: One argument is a scalar +% Emulating the sparse matrix case here, which creates and returns +% a dense result, even if the scalar is zero. + +% Case 1a: Second argument is a scalar or a dense tensor +if isscalar(B) || isa(B,'tensor') + C = full(A) - B; + return; +end + +% Case 1b: First argument is a scalar or a dense tensor +if isscalar(A) || isa(A,'tensor') + C = A - full(B); + return; +end + +%% Case 2: Both are sparse tensors +if ~isa(A,'sptensor') || ~isa(B,'sptensor') || ~isequal(size(A),size(B)) + error('Must be two sparse tensors of the same size'); +end + +C = sptensor([A.subs; B.subs], [A.vals; -B.vals], size(A)); diff --git a/external/tensor_toolbox_2.5/@sptensor/mldivide.m b/external/tensor_toolbox_2.5/@sptensor/mldivide.m new file mode 100755 index 0000000..1415916 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/mldivide.m @@ -0,0 +1,37 @@ +function C = mldivide(A,B) +%MLDIVIDE Slash left division for sparse tensors. +% +% MlDIVIDE(A,B) is called for the syntax 'A \ B' when A is a scalar and B +% is a sparse tensor. +% +% Example +% X = sptenrand([4 3 2],5); +% 3 \ X +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isscalar(A) + newsubs = B.subs; + newvals = B.vals / A; + if A == 0 + nansubs = setdiff(allsubs(A),newsubs,'rows'); + newsubs = [newsubs; nansubs]; + newvals = [newvals; repmat(NaN,size(nansubs,1),1)]; + end + C = sptensor(newsubs,newvals,B.size); + return; +end + +error('MLDIVIDE only supports the scalar case for sparse tensors'); diff --git a/external/tensor_toolbox_2.5/@sptensor/mrdivide.m b/external/tensor_toolbox_2.5/@sptensor/mrdivide.m new file mode 100755 index 0000000..7a92dce --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/mrdivide.m @@ -0,0 +1,37 @@ +function C = mrdivide(A,B) +%MRDIVIDE Slash right division for sparse tensors. +% +% MRDIVIDE(A,B) is called for the syntax 'A / B' when A is a sparse +% tensor and B is a scalar. +% +% Example +% X = sptenrand([4 3 2],5); +% X / 3 +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isscalar(B) + newsubs = A.subs; + newvals = A.vals / B; + if B == 0 + nansubs = setdiff(allsubs(A),newsubs,'rows'); + newsubs = [newsubs; nansubs]; + newvals = [newvals; repmat(NaN,size(nansubs,1),1)]; + end + C = sptensor(newsubs,newvals,A.size); + return; +end + +error('MRDIVIDE only supports the scalar case for sparse tensors'); diff --git a/external/tensor_toolbox_2.5/@sptensor/mtimes.m b/external/tensor_toolbox_2.5/@sptensor/mtimes.m new file mode 100755 index 0000000..684977a --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/mtimes.m @@ -0,0 +1,35 @@ +function C = mtimes(A,B) +%MTIMES sptensor-scalar multiplication. +% +% C = MTIMES(A,B) is called for the syntax 'A * B' when A or B is a +% sparse tensor and the other argument is a scalar. +% +% For tensor-matrix multiplication, use TTM. +% For tensor-tensor multiplication, use TTT. +% For tensor-tensor array multiplication, use TIMES or 'A .* B'. +% +% See also SPTENSOR, SPTENSOR/TTM, SPTENSOR/TTT, SPTENSOR/TIMES +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isscalar(B) + C = sptensor(A.subs, A.vals * B, size(A)); + return; +end + +if isscalar(A) + C = sptensor(B.subs, B.vals * A, size(B)); + return; +end + +error('MTIMES only supports the scalar case for sparse tensors'); diff --git a/external/tensor_toolbox_2.5/@sptensor/mttkrp.m b/external/tensor_toolbox_2.5/@sptensor/mttkrp.m new file mode 100755 index 0000000..f55b741 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/mttkrp.m @@ -0,0 +1,44 @@ +function V = mttkrp(X,U,n) +%MTTKRP Matricized tensor times Khatri-Rao product for sparse tensor. +% +% V = MTTKRP(X,U,n) efficiently calculates the matrix product of the +% n-mode matricization of X with the Khatri-Rao product of all +% entries in U, a cell array of matrices, except the nth. How to +% most efficiently do this computation depends on the type of tensor +% involved. +% +% See also SPTENSOR, TENSOR/MTTKRP, SPTENSOR/TTV +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% In the sparse case, it is most efficient to do a series of TTV operations +% rather than forming the Khatri-Rao product. + +N = ndims(X); + +if (n == 1) + R = size(U{2},2); +else + R = size(U{1},2); +end + +V = zeros(size(X,n),R); +for r = 1:R + % Set up cell array with appropriate vectors for ttv multiplication + Z = cell(N,1); + for i = [1:n-1,n+1:N] + Z{i} = U{i}(:,r); + end + % Perform ttv multiplication + V(:,r) = double(ttv(X, Z, -n)); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/ndims.m b/external/tensor_toolbox_2.5/@sptensor/ndims.m new file mode 100755 index 0000000..6156c08 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/ndims.m @@ -0,0 +1,24 @@ +function n = ndims(t) +%NDIMS Number of dimensions of a sparse tensor. +% +% NDIMS(T) returns the number of dimensions of sparse tensor T. +% +% Examples: +% T = sptenrand([3 2 2],5); +% ndims(T) %<-- should return 3 +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +n = size(t.size,2); diff --git a/external/tensor_toolbox_2.5/@sptensor/ne.m b/external/tensor_toolbox_2.5/@sptensor/ne.m new file mode 100755 index 0000000..17deae4 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/ne.m @@ -0,0 +1,82 @@ +function z = ne(x,y) +%NE Not equal (~=) for sptensors. +% +% A ~= B compares the elements of A and B for equality. The arguments can +% be a pair of sptensors, an sptensor and a tensor, or an sptensor and a +% scalar. Regardless, the result is always returned as a sparse tensor. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a ~= 5 is sparse. +% The result of a ~= 0 is sparse. +% The result of a ~= full(a) is sparse. + +%% Case 1: One argument is a scalar +if isscalar(y) + if y == 0 + z = sptensor(x.subs,true,size(x)); + else + subs1 = x.subs(x.vals ~= y,:); + subs2 = setdiff(allsubs(x),x.subs,'rows'); + z = sptensor([subs1;subs2],true,size(x)); + end + return; +end + +% Call back with the arguments reversed. +if isscalar(x) + z = ne(y,x); + return; +end + +%% Case 2: Both x and y are tensors or some sort +% Check that the sizes match +if ~isequal(x.size,y.size) + error('Size mismatch'); +end + +% Case 2a: Two sparse tensors +if isa(x,'sptensor') && isa(y,'sptensor') + + % find entries where either x *or* y is nonzero, but not both + subs1 = setxor(x.subs,y.subs,'rows'); + % find entries where both are nonzero, but inequal + subs2 = intersect(x.subs,y.subs,'rows'); + subs2 = subs2(extract(x,subs2) ~= extract(y,subs2),:); + % put it all together + z = sptensor([subs1;subs2],true,size(x)); + return; + +end + +% Case 2b: y is a dense tensor +if isa(y,'tensor') + + % find entries where x is zero but y is nonzero + subs1 = setdiff(allsubs(x),union(x.subs,find(y == 0),'rows'),'rows'); + + % find entries where x is nonzero but not equal to y + subs2 = x.subs(x.vals ~= y(x.subs,'extract'),:); + + % put it all together + z = sptensor([subs1;subs2],true,size(x)); + return; + +end + + +%% Otherwise +error('The arguments must be two sptensors or an sptensor and a scalar.'); diff --git a/external/tensor_toolbox_2.5/@sptensor/nnz.m b/external/tensor_toolbox_2.5/@sptensor/nnz.m new file mode 100755 index 0000000..496ff84 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/nnz.m @@ -0,0 +1,24 @@ +function a = nnz(t) +%NNZ Number of nonzeros in sparse tensor. +% +% NNZ(T) is the number of nonzero elements in T. +% +% See also SPTENSOR, SPTENSOR/FIND. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(t.subs) + a = 0; +else + a = size(t.subs,1); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/norm.m b/external/tensor_toolbox_2.5/@sptensor/norm.m new file mode 100755 index 0000000..051197b --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/norm.m @@ -0,0 +1,22 @@ +function nrm = norm(T) +%NORM Frobenius norm of a sparse tensor. +% +% NORM(T) returns the Frobenius norm of a sparse tensor. +% +% See also SPTENSOR, NORM. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +nrm = norm(T.vals); + +return; diff --git a/external/tensor_toolbox_2.5/@sptensor/not.m b/external/tensor_toolbox_2.5/@sptensor/not.m new file mode 100755 index 0000000..303e42a --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/not.m @@ -0,0 +1,28 @@ +function y = not(x) +%NOT Logical NOT (~) for sptensors. +% +% ~X performs a logical not on the input tensor X. The result always +% returned as a sparse tensor. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of ~a is sparse. + +%% Then compute those indicies that are not in x +subs = setdiff(allsubs(x),x.subs,'rows'); + +%% Assemble final result +y = sptensor(subs,true,x.size); diff --git a/external/tensor_toolbox_2.5/@sptensor/nvecs.m b/external/tensor_toolbox_2.5/@sptensor/nvecs.m new file mode 100755 index 0000000..c9bcad9 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/nvecs.m @@ -0,0 +1,62 @@ +function u = nvecs(t,n,r,opts) +%NVECS Compute the leading mode-n vectors for a sparse tensor. +% +% U = NVECS(X,n,r) computes the r leading eigenvalues of Xn*Xn' +% (where Xn is the mode-n matricization of X), which provides +% information about the mode-n fibers. In two-dimensions, the r +% leading mode-1 vectors are the same as the r left singular vectors +% and the r leading mode-2 vectors are the same as the r right +% singular vectors. +% +% U = NVECS(X,n,r,OPTS) specifies options: +% OPTS.eigsopts: options passed to the EIGS routine [struct('disp',0)] +% OPTS.flipsign: make each column's largest element positive [true] +% +% See also SPTENSOR, SPTENMAT, EIGS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~exist('opts','var') + opts = struct; +end + + +if isfield(opts,'eigsopts') + eigsopts = opts.eigsopts; +else + eigsopts.disp = 0; +end + +tnt = double(sptenmat(t,n,'t')); +y = tnt' * tnt; +opts.disp = 0; +[u,d] = eigs(y,r,'LM',eigsopts); + +%tn = sptenmat(t,n); +%[u,d] = eigs(@(x)aatx(tn,x), size(t,n), r, 'LM', eigsopts); + +if isfield(opts,'flipsign') + flipsign = opts.flipsign; +else + flipsign = true; +end + +if flipsign + % Make the largest magnitude element be positive + [val,loc] = max(abs(u)); + for i = 1:r + if u(loc(i),i) < 0 + u(:,i) = u(:,i) * -1; + end + end +end diff --git a/external/tensor_toolbox_2.5/@sptensor/ones.m b/external/tensor_toolbox_2.5/@sptensor/ones.m new file mode 100755 index 0000000..2a2cdfb --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/ones.m @@ -0,0 +1,21 @@ +function t = ones(t) +%ONES Replace nonzero elements of sparse tensor with ones. +% +% S = ONES(T) generates a sparse tensor with the same sparsity +% structure as T, but with ones in the nonzero position. +% +% See also SPTENSOR, SPONES. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +t.vals = ones(size(t.vals)); diff --git a/external/tensor_toolbox_2.5/@sptensor/or.m b/external/tensor_toolbox_2.5/@sptensor/or.m new file mode 100755 index 0000000..9a77a9e --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/or.m @@ -0,0 +1,45 @@ +function C = or(A,B) +%OR Logical OR (|) for sptensors. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a | 5 is dense! +% The result of a | 0 is dense! +% The result of a | full(a) is dense! +% The result of a | a is sparse. + +%% Case 1: One argument is a scalar +if isscalar(B) || isa(B,'tensor') + C = full(A) | B; + return; +end +if isscalar(A) + C = A | full(B); + return; +end + +%% Case 2: Both A and B are sparse tensors +if ~isequal(size(A),size(B)) + error('Must be tensors of the same size'); +end + +if isa(A,'sptensor') && isa(B,'sptensor') + C = sptensor([A.subs; B.subs], 1, size(A), @(x) length(x) >= 1); + return; +end + +%% Otherwise +error('The arguments must be two sptensors or an sptensor and a scalar.'); diff --git a/external/tensor_toolbox_2.5/@sptensor/permute.m b/external/tensor_toolbox_2.5/@sptensor/permute.m new file mode 100755 index 0000000..7bac392 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/permute.m @@ -0,0 +1,37 @@ +function t = permute(t,order) +%PERMUTE Rearrange the dimensions of a sparse tensor. +% +% B = PERMUTE(A,ORDER) rearranges the dimensions of A so that they +% are in the order specified by the vector ORDER. The result has the +% same values of A, but the order of the subscripts needed to access +% any particular element are rearranged as specified by ORDER. +% +% See also SPTENSOR, PERMUTE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Error checking +if (ndims(order) ~= 2) || (size(order,1) ~= 1) + error('ORDER must be a row vector'); +end + +% Check that the permuation is valid +if ~isequal(sort(order),1:ndims(t)) + error('Invalid permutation.'); +end + +% Do the permutation +if ~isempty(t.subs) + t.subs = t.subs(:,order); +end +t.size = t.size(order); diff --git a/external/tensor_toolbox_2.5/@sptensor/plus.m b/external/tensor_toolbox_2.5/@sptensor/plus.m new file mode 100755 index 0000000..e0ffb34 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/plus.m @@ -0,0 +1,56 @@ +function C = plus(A,B) +%PLUS Binary addition for sparse tensors. +% +% PLUS(A,B) is called for the syntax 'A + B' when A or B is a sparse +% tensor. A and B must have the same size, unless one is a scalar. A +% scalar can be added to a sparse tensor of any size. +% +% Examples +% A = sptenrand([4 3 2],5); B = sptenrand([4 3 2],3); +% A + B %<-- sparse +% A + 5 %<-- dense +% A + 0 %<-- dense +% A + full(A) %<-- dense +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +%% Observations for sparse matrix case. +% The result of a + 5 is dense! +% The result of a + 0 is dense! +% The result of a + full(a) is dense! +% The result of a + b (two sparse matrices) is sparse. + +%% Case 1: One argument is a scalar +% Emulating the sparse matrix case here, which creates and returns +% a dense result, even if the scalar is zero. + +% Case 1a: Second argument is a scalar or a dense tensor +if isscalar(B) || isa(B,'tensor') + C = full(A) + B; + return; +end + +% Case 1b: First argument is a scalar +if isscalar(A) + C = A + full(B); + return; +end + +%% Case 2: Both are sparse tensors + +if ~isa(A,'sptensor') || ~isa(B,'sptensor') || ~isequal(size(A),size(B)) + error('Must be two sparse tensors of the same size'); +end + +C = sptensor([A.subs; B.subs], [A.vals; B.vals], size(A)); diff --git a/external/tensor_toolbox_2.5/@sptensor/private/allsubs.m b/external/tensor_toolbox_2.5/@sptensor/private/allsubs.m new file mode 100755 index 0000000..a498107 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/private/allsubs.m @@ -0,0 +1,34 @@ +function s = allsubs(x) +%ALLSUBS Generate all possible subscripts for a sparse tensor X. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Generate all possible indicies + +% Preallocate (discover any memory issues here!) +s = zeros(prod(x.size),ndims(x)); + +% Generate appropriately sized ones vectors. +o = cell(ndims(x),1); +for n = 1:ndims(x) + o{n} = ones(size(x,n),1); +end + +% Generate each column of the subscripts in turn +for n = 1:ndims(x) + i = o; + i{n} = (1:size(x,n))'; + s(:,n) = khatrirao(i); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/private/extract.m b/external/tensor_toolbox_2.5/@sptensor/private/extract.m new file mode 100755 index 0000000..7a7c200 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/private/extract.m @@ -0,0 +1,47 @@ +function a = extract(t,srchsubs) +%EXTRACT Extract value for a sptensor. +% +% EXTRACT(X,SUBS) returns a list of values. +% +% See also SPTENSOR/SUBSREF. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +% Check range of requested subscripts +p = size(srchsubs,1); + +% Check that all subscripts are positive and less than the max +invalid = (srchsubs < 0) | (srchsubs > ones(p,1)*t.size); +badloc = find(sum(invalid,2)); +if ~isempty(badloc) + fprintf('The following subscripts are invalid: \n'); + badsubs = srchsubs(badloc,:); + badidx = tt_sub2ind(size(t),badsubs); + for i = 1:numel(badloc) + fprintf('\tsubscript = %s (linear index = %d)\n',... + tt_intvec2str(badsubs(i,:)), badidx(i)); + end + error('Invalid subscripts'); +end + +% Set the default answer to zero +a = zeros(p,1); + +% Find which indices already exist and their locations +[tf,loc] = ismember(srchsubs,t.subs,'rows'); + +% Fill in the non-zero elements in the answer +nzsubs = find(tf); +a(nzsubs,1) = t.vals(loc(nzsubs)); + diff --git a/external/tensor_toolbox_2.5/@sptensor/private/irenumber.m b/external/tensor_toolbox_2.5/@sptensor/private/irenumber.m new file mode 100755 index 0000000..7480142 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/private/irenumber.m @@ -0,0 +1,35 @@ +function newsubs = irenumber(t, sz, range) +%RENUMBER indices for sptensor subsasgn +% +% See also SPTENSOR/SUBSASGN +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +nz = nnz(t); +if (nz == 0) + newsubs = []; + return; +end + +newsubs = t.subs; +for i = 1 : numel(range) + r = range{i}; + if ischar(r) && r == ':' + continue; + elseif numel(r) == 1 + newsubs = [newsubs(:,1:i-1), r*ones(nz,1), newsubs(:,i:end)]; + else + newsubs(:,i) = r(newsubs(:,i)); + end +end + diff --git a/external/tensor_toolbox_2.5/@sptensor/private/renumber.m b/external/tensor_toolbox_2.5/@sptensor/private/renumber.m new file mode 100755 index 0000000..c2fcc2b --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/private/renumber.m @@ -0,0 +1,52 @@ +function [newsubs, newsz] = renumber(subs, sz, range) +%RENUMBER indices for sptensor subsref +% +% [NEWSUBS,NEWSZ] = RENUMBER(SUBS,SZ,RANGE) takes a set of +% original subscripts SUBS with entries from a tensor of size +% SZ. All the entries in SUBS are assumed to be within the +% specified RANGE. These subscripts are then renumbered so that, +% in dimension i, the numbers range from 1:numel(RANGE(i)). +% +% See also SPTENSOR/SUBSREF +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +newsz = sz; +newsubs = subs; +for i = 1 : size(sz,2) + if ~(ischar(range{i}) && range{i} == ':') + if (isempty(subs)) + newsz(i) = numel(range{i}); + else + [newsubs(:,i), newsz(i)] = ... + renumberdim(subs(:,i), sz(i), range{i}); + end + end +end + +%------------------------------------------------------ +function [newidx, newsz] = renumberdim(idx, sz, range) +%RENUMBERDIM helper function for RENUMBER +% See also SPTENSOR/PRIVATE/RENUMBER + +% Determine the size of the new range +newsz = numel(range); + +% Create a map from the old range to the new range +map = zeros(1, sz); +for i = 1 : newsz + map(range(i)) = i; +end + +% Do the mapping +newidx = map(idx); diff --git a/external/tensor_toolbox_2.5/@sptensor/private/subdims.m b/external/tensor_toolbox_2.5/@sptensor/private/subdims.m new file mode 100755 index 0000000..e9658d2 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/private/subdims.m @@ -0,0 +1,63 @@ +function loc = subdims(subd, t) +%SUBDIMS Compute the locations of subscripts within a subdimension. +% +% LOC = SUBDIMS(SUBD,T) finds the locations of the subscripts in T +% that are within the range specified by the cell array SUBD. For +% example, if SUBD = {1, [1,2], [1,2]}, then the locations of +% all elements of T that have a first subscript equal to 1, a +% second subscript equal to 1 or 2, and a third subscript equal to +% 1 or 2 is returned. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Error check that subd is the right size +if size(subd,2) ~= ndims(t) + error('Number of subdimensions must equal number of dimensions'); +end + +% Error check that range is valid +for i = 1 : ndims(t) + r = subd{i}; + okcolon = ischar(r) && r == ':'; + oknumeric = isreal(r) && ~any(isnan(r(:))) && ~any(isinf(r(:))) ... + && isequal(r,round(r)) && all(r(:) > 0); + if ~(okcolon || oknumeric) + error('Invalid subdimension.'); + end +end + +% Copy out the subscripts from t +subs = t.subs; + +if isempty(subs) + loc = []; + return; +end + +% Compute the indices of the subscripts that are within the +% specified range. We start with all indices in loc and +% pare it down to a final list. + +loc = (1:size(subs,1))'; +for i = 1:ndims(t) + if ~(ischar(subd{i}) && subd{i} == ':') + + % Find the subscripts that match in dimension i + tf = ismember(subs(loc,i), subd{i}); + + % Pare down the list of indices + loc = loc(tf); + + end +end + diff --git a/external/tensor_toolbox_2.5/@sptensor/rdivide.m b/external/tensor_toolbox_2.5/@sptensor/rdivide.m new file mode 100755 index 0000000..7ac575c --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/rdivide.m @@ -0,0 +1,107 @@ +function C = rdivide(A,B) +%RDIVIDE Array right division for sparse tensors. +% +% RDIVIDE(A,B) is called for the syntax 'A ./ B' when A or B is a sparse +% tensor. A and B must have the same size, unless one is a scalar. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% a ./ 5 -> sparse +% 5 ./ a -> dense! +% a ./ full(a) -> sparse! +% full(a) ./ a -> dense + +% Divide by a scalar -> result is sparse +if isscalar(B) + C = mrdivide(A,B); + return; +end + +% Scalar divided by a tensor -> result is dense +if isscalar(A) + C = A ./ full(B); + return; +end + +% Tensor divided by a tensor +if ~isequal(size(A),size(B)) + error('Must be two tensors of the same size'); +end + +% Two sparse tensors +if isa(A,'sptensor') && isa(B,'sptensor') + + % Find where their zeros are + if isempty(A.subs) + Azerosubs = allsubs(A); + else + Azerosubs = setdiff(allsubs(A),A.subs,'rows'); + end + if isempty(B.subs) + Bzerosubs = allsubs(B); + else + Bzerosubs = setdiff(allsubs(B),B.subs,'rows'); + end + + % Both nonzero + [newsubs,ia,ib] = intersect(A.subs,B.subs,'rows'); + newvals = A.vals(ia) ./ B.vals(ib); + + % A nonzero and B zero + moresubs = intersect(A.subs,Bzerosubs,'rows'); + morevals = repmat(Inf, size(moresubs,1),1); + newsubs = [newsubs; moresubs]; + newvals = [newvals; morevals]; + + % Both zero + moresubs = intersect(Azerosubs,Bzerosubs,'rows'); + morevals = repmat(NaN, size(moresubs,1),1); + newsubs = [newsubs; moresubs]; + newvals = [newvals; morevals]; + + C = sptensor(newsubs,newvals,size(A)); + return; +end + +% Some other tensor type! +switch class(B) + case {'tensor'} + csubs = A.subs; + cvals = A.vals ./ B(csubs); + C = sptensor(csubs, cvals, size(A)); + return; + case {'ktensor'} + R = numel(B.lambda); + N = ndims(A); + NZ = nnz(A); + csubs = A.subs; + avals = A.vals; + bvals = zeros(NZ,1); + for r = 1:R + tvals = B.lambda(r) * ones(NZ,1); + for n = 1:N + v = B{n}(:,r); + tvals = tvals .* v(csubs(:,n)); + end + bvals = bvals + tvals; + end + cvals = avals ./ bvals; + C = sptensor(csubs, cvals, size(A)); + return; +end + +error('Invalid arguments for RDIVIDE.'); + diff --git a/external/tensor_toolbox_2.5/@sptensor/reshape.m b/external/tensor_toolbox_2.5/@sptensor/reshape.m new file mode 100755 index 0000000..eabc706 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/reshape.m @@ -0,0 +1,44 @@ +function a = reshape(a,new_size,old_modes) +%RESHAPE Reshape sparse tensor. +% +% RESHAPE(X,SIZ) reshapes the sparse tensor to the given size. PROD(SIZ) +% must be the same as PROD(SIZE(X)). +% +% RESHAPE(X,SIZ,MODES) reshapes only the specifies modes and appends the +% new reshaped modes to the end of the indices. +% +% See also SPTENSOR, SPTENSOR/PERMUTE, RESHAPE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~exist('old_modes','var') + old_modes = 1:ndims(a); + keep_modes = []; +else + keep_modes = setdiff(1:ndims(a),old_modes); +end +old_size = a.size(old_modes); +keep_size = a.size(keep_modes); + + +if prod(new_size) ~= prod(old_size) + error('prod(SIZ) must be the same size of prod(SIZE(X,MODES))'); +end + +inds = tt_sub2ind(old_size,a.subs(:,old_modes)); +new_subs = tt_ind2sub(new_size,inds); + +a.size = [keep_size new_size]; +a.subs = [a.subs(:,keep_modes) new_subs]; + + diff --git a/external/tensor_toolbox_2.5/@sptensor/scale.m b/external/tensor_toolbox_2.5/@sptensor/scale.m new file mode 100755 index 0000000..1e903fa --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/scale.m @@ -0,0 +1,50 @@ +function t = scale(t,s,dims) +%SCALE Scale along specified dimensions for sparse tensors. +% +% Y = SCALE(X,S,DIMS) scales the sparse tensor X along the +% dimension(s) specified in DIMS using the scaling data in S. If +% DIMS contains only one dimensions, then S can be a column +% vector. Otherwise, S should be a tensor or sparse tensor. +% +% Examples +% X = ones(sptenrand([3 4 5], 10)) +% S = 10 * [1:5]'; Y = scale(X,S,3) +% S = tensor(10 * [1:5]',5); Y = scale(X,S,3) +% S = tensor(1:12,[3 4]); Y = scale(X,S,[1 2]) +% S = tensor(1:12,[3 4]); Y = scale(X,S,-3) +% +% See also SPTENSOR, SPTENSOR/COLLAPSE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +dims = tt_dimscheck(dims,ndims(t)); + +switch(class(s)) + case {'tensor'} + if ~isequal(size(s), t.size(dims)) + error 'Size mismatch'; + end + t.vals = t.vals .* s(t.subs(:,dims),'extract'); + case {'sptensor'} + if ~isequal(s.size, t.size(dims)) + error 'Size mismatch'; + end + t.vals = t.vals .* extract(s,(t.subs(:,dims))); + case {'double'} + if size(s,1) ~= t.size(dims) + error 'Size mismatch'; + end + t.vals = t.vals .* s(t.subs(:,dims)); + otherwise + error('Invalid scaling factor'); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/size.m b/external/tensor_toolbox_2.5/@sptensor/size.m new file mode 100755 index 0000000..79b0388 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/size.m @@ -0,0 +1,26 @@ +function m = size(t,idx) +%SIZE Sparse tensor dimensions. +% +% D = SIZE(T) returns the size of the tensor. +% +% I = size(T,DIM) returns the sizes of the dimensions specified by DIM. +% +% See also SPTENSOR, SPTENSOR/NDIMS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if exist('idx','var') + m = t.size(idx); +else + m = t.size; +end diff --git a/external/tensor_toolbox_2.5/@sptensor/spmatrix.m b/external/tensor_toolbox_2.5/@sptensor/spmatrix.m new file mode 100755 index 0000000..a6e41fa --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/spmatrix.m @@ -0,0 +1,30 @@ +function s = spmatrix(a) +%SPMATRIX Converts a two-way sparse tensor to sparse matrix. +% +% SPMATRIX(X) converts a sparse tensor to a sparse matrix. The sparse +% tensor must be two-dimensional. +% +% See also SPTENSOR, SPTENSOR/RESHAPE, SPTENMAT +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ndims(a) ~= 2 + error('Sparse tensor must be two dimensional.'); +end + + +if isempty(a.subs) + s = sparse(a.size(1), a.size(2)); +else + s = sparse(a.subs(:,1), a.subs(:,2), a.vals, a.size(1), a.size(2)); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/sptensor.m b/external/tensor_toolbox_2.5/@sptensor/sptensor.m new file mode 100755 index 0000000..474d2c0 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/sptensor.m @@ -0,0 +1,250 @@ +function t = sptensor(varargin) +%SPTENSOR Create a sparse tensor. +% +% X = SPTENSOR(SUBS, VALS, SZ, FUN) uses the rows of SUBS and VALS +% to generate a sparse tensor X of size SZ = [m1 m2 ... mn]. SUBS is +% an p x n array specifying the subscripts of the values to be +% inserted into S. The k-th row of SUBS specifies the subscripts for +% the k-th value in VALS. The values are accumulated at repeated +% subscripts using the function FUN, which is specified by a +% function handle. +% +% There are several simplifications of this four argument call. +% +% X = SPTENSOR(SUBS,VALS,SZ) uses FUN=@SUM. +% +% X = SPTENSOR(SUBS,VALS) uses SM = max(SUBS,[],1). +% +% X = SPTENSOR(SZ) abbreviates X = SPTENSOR([],[],SZ). +% +% X = SPTENSOR(Y) copies/converts Y if it is an sptensor, an sptenmat, or +% a dense tensor or MDA (the zeros are squeezed out), an sptensor3, or a +% sparse matrix. Note that a row-vector, integer MDA is interpreted as a +% size (see previous constructor). +% +% S = SPTENSOR is the empty constructor. +% +% The argument VALS may be scalar, which is expanded to be the +% same length as SUBS, i.e., it is equivalent to VALS*(p,1). +% +% Examples +% subs = [1 1 1; 1 1 3; 2 2 2; 4 4 4; 1 1 1; 1 1 1] +% vals = [0.5; 1.5; 2.5; 3.5; 4.5; 5.5] +% siz = [4 4 4]; +% X = sptensor(subs,vals,siz) %<-- sparse 4x4x4, repeats summed +% X = sptensor(subs,1,siz) %<-- scalar 2nd argument +% X = sptensor(subs,vals,siz,@max) %<-- max for accumulation +% myfun = @(x) sum(x) / 3; +% X = sptensor(subs,vals,siz,myfun) %<-- custom accumulation +% +% See also SPTENRAND, TENSOR, SPTENMAT, SPTENSOR3, ACCUMARRAY +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% EMPTY Constructor +if (nargin == 0) || ((nargin == 1) && isempty(varargin{1})) + t.subs = []; + t.vals = []; + t.size = []; + t = class(t,'sptensor'); + return; +end + +% SINGLE ARGUMENT +if (nargin == 1) + + source = varargin{1}; + + switch(class(source)) + + % COPY CONSTRUCTOR + case 'sptensor', + t.subs = source.subs; + t.vals = source.vals; + t.size = source.size; + t = class(t, 'sptensor'); + return; + + % CONVERT SPTENMAT + case 'sptenmat', + + % Extract the tensor size and order + siz = source.tsize; + + % Convert the 2d-subscipts into nd-subscripts + if ~isempty(source.rdims) + subs(:,source.rdims) = ... + tt_ind2sub(siz(source.rdims),source.subs(:,1)); + end + if ~isempty(source.cdims) + subs(:,source.cdims) = ... + tt_ind2sub(siz(source.cdims),source.subs(:,2)); + end + + % Copy the values (which do not need to be modified) + vals = source.vals; + + % Store everything + t.subs = subs; + t.vals = vals; + t.size = siz; + t = class(t, 'sptensor'); + return; + + % CONVERT TENSOR + case 'tensor', + [subs,vals] = find(source); + t.subs = subs; + t.vals = vals; + t.size = size(source); + t = class(t, 'sptensor'); + return; + + % CONVERT SPTENSOR3 + case 'sptensor3', + K = size(source,3); + [I,J] = size(source{1}); + nz = nnz(K); + bigsubs = []; + bigvals = []; + for k = 1:K + [subs,vals] = find(source{k}); + if isempty(bigsubs) + bigsubs = [subs, k*ones(size(subs,1),1)]; + bigvals = [vals]; + else + bigsubs = [bigsubs; subs, k*ones(size(subs,1),1)]; + bigvals = [bigvals; vals]; + end + end + t.subs = bigsubs; + t.vals = bigvals; + t.size = [ I J K ]; + t = class(t,'sptensor'); + return; + + % SPARSE MATRIX, SIZE, or MDA + case {'numeric','logical','double'}, + + % Case 1: SPARSE MATRIX + if issparse(source) + [i,j,s] = find(source); + siz = size(source); + t.subs = [i,j]; + t.vals = s; + t.size = siz; + t = class(t,'sptensor'); + return; + end + + % Case 2: SPECIFYING THE SIZE + if tt_sizecheck(source) + t.subs = []; + t.vals = []; + t.size = source; + t = class(t, 'sptensor'); + return; + end + + % Case 3: An MDA + t = sptensor(tensor(source)); + return; + + end % switch + +end % nargin == 1 + +% SPECIAL CASE for INTERACTION WITH MEX FILES +if (nargin == 4) && (isnumeric(varargin{4})) && (varargin{4} == 0) + + % Store everything + t.subs = varargin{1}; + t.vals = varargin{2}; + t.size = varargin{3}; + + % Create the tensor + t = class(t, 'sptensor'); + + return; + +end + +% CONVERT A SET OF INPUTS +if (nargin == 2) || (nargin == 3) || (nargin == 4) + + % Extract the subscripts and values + subs = varargin{1}; + vals = varargin{2}; + + tt_subscheck(subs); + tt_valscheck(vals); + if ~isempty(vals) && (numel(vals) ~= 1) && (size(vals,1) ~= size(subs,1)) + error('Number of subscripts and values must be equal'); + end + + % Extract the size + if (nargin > 2) + siz = varargin{3}; + tt_sizecheck(siz); + else + siz = max(subs,[],1); + end + + % Check for wrong input + if size(subs,2) > size(siz,2) + error('More subscripts than specified by size') + end + + % Check for subscripts out of range + for j = 1:numel(siz) + if ~isempty(subs) && max(subs(:,j)) > siz(j) + error('Subscript exceeds sptensor size') + end + end + + % Extract the 'combiner' function handle + if (nargin == 4) + fun = varargin{4}; + else + fun = @sum; + end + + if isempty(subs) + newsubs = []; + newvals = []; + else + % Identify only the unique indices + [newsubs,junk,loc] = unique(subs,'rows'); + + % Sum the corresponding values + newvals = accumarray(loc,vals,[size(newsubs,1) 1],fun); + end + + % Find the nonzero indices of the new values + nzidx = find(newvals); + newsubs = newsubs(nzidx,:); + newvals = newvals(nzidx); + + % Store everything + t.subs = newsubs; + t.vals = newvals; + t.size = siz; + + % Create the tensor + t = class(t, 'sptensor'); + + return; +end + +error('Unsupported use of function SPTENSOR.'); + diff --git a/external/tensor_toolbox_2.5/@sptensor/squeeze.m b/external/tensor_toolbox_2.5/@sptensor/squeeze.m new file mode 100755 index 0000000..53e9289 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/squeeze.m @@ -0,0 +1,45 @@ +function Y = squeeze(X) +%SQUEEZE Remove singleton dimensions from a sparse tensor. +% +% Y = SQUEEZE(X) returns a sparse tensor Y with the same elements as +% X but with all the singleton dimensions removed. A singleton +% is a dimension such that size(X,dim)==1. +% +% If X has *only* singleton dimensions, then Y is a scalar. +% +% Examples +% squeeze( sptenrand([2,1,3],0.5) ) %<-- returns a 2-by-3 sptensor +% squeeze( sptensor([1 1 1],1,[1 1 1]) ) %<-- returns a scalar +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if all(X.size > 1) + % No singleton dimensions to squeeze + Y = X; +else + idx = find(X.size > 1); + if numel(idx) == 0 + % Scalar case - only singleton dimensions + Y = X.vals; + else + siz = X.size(idx); + if isempty(X.vals) + Y = sptensor([],[],siz); + else + Y = sptensor(X.subs(:,idx), X.vals, siz); + end + end +end + +return; diff --git a/external/tensor_toolbox_2.5/@sptensor/subsasgn.m b/external/tensor_toolbox_2.5/@sptensor/subsasgn.m new file mode 100755 index 0000000..adf1e5f --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/subsasgn.m @@ -0,0 +1,317 @@ +function t = subsasgn(t,s,rhs) +%SUBSASGN Subscripted assignment for sparse tensor. +% +% We can assign elements to a sptensor in three ways. +% +% Case 1: X(R1,R2,...,RN) = Y, in which case we replace the +% rectangular subtensor (or single element) specified by the ranges +% R1,...,RN with Y. The right-hand-side can be a scalar or an +% sptensor. +% +% Case 2: X(S) = V, where S is a p x n array of subscripts and V is +% a scalar value or a vector containing p values. +% +% Linear indexing is not supported for sparse tensors. +% +% Examples +% X = sptensor([30 40 20]) %<-- Create an emtpy 30 x 40 x 20 sptensor +% X(30,40,20) = 7 %<-- Assign a single element to be 7 +% X([1,1,1;2,2,2]) = 1 %<-- Assign a list of elements to the same value +% X(11:20,11:20,11:20) = sptenrand([10,10,10],10) %<-- subtensor! +% X(31,41,21) = 7 %<-- grows the size of the tensor +% X(111:120,111:120,111:120) = sptenrand([10,10,10],10) %<-- grows +% X(1,1,1,1) = 4 %<-- increases the number of dimensions from 3 to 4 +% +% X = sptensor([30]) %<-- empty one-dimensional tensor +% X([4:6]) = 1 %<-- set subtensor to ones (does not increase dimension) +% X([10;12;14]) = (4:6)' %<-- set three elements +% X(31) = 7 %<-- grow the first dimension +% X(1,1) = 0 %<-- add a dimension, but no nonzeros +% +% Note regarding singleton dimensions: It is not possible to do, for +% instance, X(1,1:10,1:10) = sptenrand([1 10 10],5). However, it is okay +% to do X(1,1:10,1:10) = squeeze(sptenrand([1 10 10],5)). +% +% See also SPTENSOR, TENSOR/SUBSASGN. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +switch s.type + + case '.' + error(['Cannot change field ', s.subs, ' directly.']); + + case '()' + + % Do nothing if both subscripts and RHS are empty + if isempty(s.subs{1}) && isempty(t.vals) + return; + end + + % Figure out if we are doing a subtensor or a list of subscripts... + type = tt_assignment_type(t,s.subs,rhs); + + %% Case I: Replace a sub-tensor + if isequal(type,'subtensor') + + %% Case I(a): RHS is another sparse tensor + if isa(rhs,'sptensor') + + %% First, Resize the tensor and check the size match with + %% the tensor that's being inserted. + m = 1; + for n = 1:numel(s.subs) + if ischar(s.subs{n}) && (s.subs{n} == ':') + if ndims(t) < n + newsz(1,n) = rhs.size(m); + else + newsz(1,n) = max([t.size(n), rhs.size(m)]); + end + m = m + 1; + elseif numel(s.subs{n}) == 1 + if ndims(t) < n + newsz(1,n) = s.subs{n}; + else + newsz(1,n) = max([t.size(n) s.subs{n}]); + end + else + if numel(s.subs{n}) ~= rhs.size(m) + error('RHS does not match range size'); + end + if ndims(t) < n + newsz(1,n) = max(s.subs{n}); + else + newsz(1,n) = max([t.size(n) s.subs{n}]); + end + m = m + 1; + end + end + t.size = newsz; + + % Expand subs array if there are new modes, i.e., if the order + % has increased. + if ~isempty(t.subs) && (size(t.size,2) > size(t.subs,2)) + t.subs(:,end+1:size(t.size,2)) = 1; + end + + % Delete what currently occupies the specified range + rmloc = subdims(s.subs,t); + kploc = setdiff(1:nnz(t),rmloc); + newsubs = t.subs(kploc,:); + newvals = t.vals(kploc); + + % Renumber the subscripts + addsubs = irenumber(rhs, t.size, s.subs); + t.subs = [newsubs; addsubs]; + t.vals = [newvals; rhs.vals]; + + return; + end + + %% Case I(b): RHS is zero or scalar + + % First, Resize the tensor. + % Determine new size of existing modes + for n = 1:ndims(t) + if ischar(s.subs{n}) && (s.subs{n} == ':') + newsz(1,n) = t.size(n); + else + newsz(1,n) = max([t.size(n) s.subs{n}]); + end + end + % Determine size of new modes, if any + for n = ndims(t)+1:numel(s.subs) + newsz(1,n) = max(s.subs{n}); + end + t.size = newsz; + + % Expand subs array if there are new modes, i.e., if the order + % has increased. + if ~isempty(t.subs) && (size(t.size,2) > size(t.subs,2)) + t.subs(:,end+1:size(t.size,2)) = 1; + end + + % Case I(b)i: Zero right-hand-side + if numel(rhs) == 1 && rhs == 0 + + % Delete what currently occupies the specified range + rmloc = subdims(s.subs,t); + kploc = setdiff(1:nnz(t),rmloc); + t.subs = t.subs(kploc,:); + t.vals = t.vals(kploc); + return; + end + + % Case I(b)ii: Scalar right-hand-side + if numel(rhs) == 1 + + % Determine number of dimensions (may be larger than + % current number) + N = numel(s.subs); + + % Figure out how many indices are in each dimension + nssubs = zeros(N,1); + for n = 1:N + if ischar(s.subs{n}) && s.subs{n} == ':' + s.subs{n} = 1:size(t,n); + end + nssubs(n) = numel(s.subs{n}); + end + + % Preallocate (discover any memory issues here!) + addsubs = zeros(prod(nssubs),N); + + % Generate appropriately sized ones vectors. + o = cell(N,1); + for n = 1:N + o{n} = ones(nssubs(n),1); + end + + % Generate each column of the subscripts in turn + for n = 1:N + i = o; + i{n} = s.subs{n}'; + addsubs(:,n) = khatrirao(i); + end + + if ~isempty(t.subs) + % replace existing values + [junk,loc] = intersect(t.subs,addsubs,'rows'); + t.vals(loc) = rhs; + % pare down list of subscripts to add + addsubs = setdiff(addsubs,t.subs,'rows'); + end + t.subs = [t.subs; addsubs]; + t.vals = [t.vals; rhs*ones(size(addsubs,1),1)]; + return; + end + + error('Invalid RHS') + + end + + % Case II: Subscripts + if isequal(type,'subscripts') + + % Case II: Replacing values at specified indices + + newsubs = [s.subs{1}]; + tt_subscheck(newsubs); + + % Error check on subscripts + if size(newsubs,2) < ndims(t) + error('Invalid subscripts'); + end + + % Check for expanding the order + if size(newsubs,2) > ndims(t) + t.size(end+1:size(newsubs,2)) = 1; + if ~isempty(t.subs) + t.subs(:,end+1:size(newsubs,2)) = 1; + end + end + + % Copy rhs to newvals + newvals = rhs; + + % Error check the RHS is a column vector. We do not bother to + % handle any other type of RHS with the sparse tensor. + tt_valscheck(newvals); + + % Determine number of nonzeros being inserted. (This is + % determined by the number of subscripts. Later we will check + % to see that it matches the size of the RHS.) + newnnz = size(newsubs,1); + + % Error check on size of newvals + if numel(newvals) == 1 + + % Special case where newvals is a single element to be + % assigned to multiple RHS. Fix to be correct size. + newvals = newvals * ones(newnnz,1); + + elseif size(newvals,1) ~= newnnz + + % Sizes don't match! + error('Number of subscripts and number of values do not match!'); + + end + + % Remove duplicates & print warning if any duplicates were + % removed. + [newsubs,idx] = unique(newsubs,'rows'); + if size(newsubs,1) ~= newnnz + warning('Duplicate assignments discarded.'); + end + newvals = newvals(idx); + + % Find which subscripts already exist and their locations + [tf,loc] = ismember(newsubs,t.subs,'rows'); + + % Split into three groups for processing: + % + % Group A: Elements that already exist and need to be changed + % Group B: Elements that already exist and need to be removed + % Group C: Elements that do not exist and need to be added + % + % Note that we are ignoring any new zero elements, because + % those obviously do not need to be added. Also, it's + % important to process Group A before Group B because the + % processing of Group B may change the locations of the + % remaining elements. + + idxa = find((tf .* newvals) ~= 0); + idxb = find((tf .* ~abs(newvals)) ~= 0); + idxc = find((~tf .* newvals) ~= 0); + + % Process Group A: Changing values + if ~isempty(idxa) + t.vals(loc(idxa)) = newvals(idxa); + end + + % Process Group B: Removing values + if ~isempty(idxb) + removesubs = loc(idxb); + keepsubs = setdiff(1:nnz(t),removesubs); + t.subs = t.subs(keepsubs,:); + t.vals = t.vals(keepsubs); + end + + % Process Group C: Adding new, nonzero values + if ~isempty(idxc) + t.subs = [t.subs; newsubs(idxc,:)]; + t.vals = [t.vals; newvals(idxc)]; + end + + % Resize the tensor! + for n = 1:length(t.size) + smax = max(newsubs(:,n)); + t.size(n) = max(t.size(n), smax); + end + + return; + + end + + error('Invalid call to sptensor/subsasgn'); + + case '{}' + error('Subscript cell reference not supported for sptensor.'); + + otherwise + error('Incorrect indexing into sptensor.') + +end + + diff --git a/external/tensor_toolbox_2.5/@sptensor/subsref.m b/external/tensor_toolbox_2.5/@sptensor/subsref.m new file mode 100755 index 0000000..f7b58ed --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/subsref.m @@ -0,0 +1,159 @@ +function a = subsref(t,s) +%SUBSREF Subscripted reference for a sparse tensor. +% +% We can extract elements or subtensors from a sparse tensor in the +% following ways. +% +% Case 1a: y = X(i1,i2,...,iN), where each in is an index, returns a +% scalar. +% +% Case 1b: Y = X(R1,R2,...,RN), where one or more Rn is a range and +% the rest are indices, returns a sparse tensor. The elements are +% renumbered here as appropriate. +% +% Case 2a: V = X(S) or V = X(S,'extract'), where S is a p x n array +% of subscripts, returns a vector of p values. +% +% Case 2b: V = X(I) or V = X(I,'extract'), where I is a set of p +% linear indices, returns a vector of p values. +% +% Any ambiguity results in executing the first valid case. This +% is particularily an issue if ndims(X)==1. +% +% S = X.subs returns the subscripts of the nonzero entries in X. +% +% V = X.vals returns the values of the nonzero entries in X. +% +% Examples +% X = sptensor([4,4,4;2,2,1;2,3,2],[3;5;1],[4 4 4]); +% X(1,2,1) %<-- returns zero +% X(4,4,4) %<-- returns 3 +% X(3:4,:,:) %<-- returns 2 x 4 x 4 sptensor +% X(2,:,:) %<-- returns a 2 x 2 tensor +% X([1,1,1;2,2,1]) %<-- returns a vector of 2 elements +% X = sptensor([6;16;26],[1;1;1],30); +% X([1:6]') %<-- extracts a subtensor +% X([1:6]','extract') %<-- extracts a vector of 6 elements +% +% See also SPTENSOR, SPTENSOR/FIND, TENSOR/SUBSREF. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +switch s(1).type + + case '{}' + error('Subscript cell reference cannot be used with sptensor.') + + case '.' + switch s(1).subs + case {'subs','indices'} + a = tt_subsubsref(t.subs, s); + case {'vals','values'} + a = tt_subsubsref(t.vals, s); + case 'size' + a = tt_subsubsref(t.size, s); + otherwise + error(['No such field: ', s(1).subs]); + end + return; + + case '()' + + % *** CASE 1: Rectangular Subtensor *** + if (numel(s(1).subs) == ndims(t)) && ... + ~isequal(s(1).subs{end},'extract') + + % Extract the subdimensions to be extracted from t + region = s(1).subs; + + % Pare down the list of subscripts (and values) to only + % those within the subdimensions specified by region. + loc = subdims(region, t); + subs = t.subs(loc,:); + vals = t.vals(loc); + + % Find the size of the subtensor and renumber the + % subscripts + [subs, sz] = renumber(subs, size(t), region); + + % Determine the subscripts + newsiz = []; % (future) new size + kpdims = []; % dimensions to keep + rmdims = []; % dimensions to remove + + % Determine the new size and what dimensions to keep + for i = 1:length(region) + if ischar(region{i}) && (region{i} == ':') + newsiz = [newsiz size(t,i)]; + kpdims = [kpdims i]; + elseif numel(region{i}) > 1 + newsiz = [newsiz numel(region{i})]; + kpdims = [kpdims i]; + else + rmdims = [rmdims i]; + end + end + + % Return a single double value for a zero-order sub-tensor + if isempty(newsiz) + if isempty(vals) + a = 0; + else + a = vals; + end + return; + end + + % Assemble the resulting sparse tensor + if isempty(subs) + a = sptensor([],[],sz(kpdims)); + else + a = sptensor(subs(:,kpdims), vals, sz(kpdims)); + end + return; + end + + % Case 2: EXTRACT + + % *** CASE 2a: Subscript indexing *** + if size(s(1).subs{1},2) == ndims(t) + + % extract array of subscripts + srchsubs = s(1).subs{1}; + + % *** CASE 2b: Linear indexing *** + else + + % Error checking + if numel(s(1).subs) ~= 1 + error('Invalid indexing'); + end + + idx = s(1).subs{1}; + if ndims(idx) ~=2 || size(idx,2) ~= 1 + error('Expecting a column index'); + end + + % extract linear indices and convert to subscripts + srchsubs = tt_ind2sub(size(t),idx); + + end + + a = extract(t,srchsubs); + a = tt_subsubsref(a,s); + + return; + + otherwise + error('Incorrect indexing into sptensor.') +end diff --git a/external/tensor_toolbox_2.5/@sptensor/times.m b/external/tensor_toolbox_2.5/@sptensor/times.m new file mode 100755 index 0000000..e8f81be --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/times.m @@ -0,0 +1,70 @@ +function C = times(A,B) +%TIMES Array multiplication for sparse tensors. +% +% TIMES(A,B) is called for the syntax 'A .* B' when A or B is a +% sparse tensor. A and B must have the same size, unless one is a scalar. +% A scalar can be multiplied by a sparse tensor of any size. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of a .* 5 is sparse. +% The result of a .* 0 is sparse. +% The result of a .* full(a) is sparse. + +%% +if isscalar(B) + C = sptensor(A.subs, A.vals * B, size(A)); + return; +end + +if isscalar(A) + C = sptensor(B.subs, B.vals * A, size(B)); + return; +end + +if ~isequal(size(A),size(B)) + error('Must be two tensors of the same size'); +end + +switch class(B) + case {'sptensor'} + [csubs,ia,ib] = intersect(A.subs,B.subs,'rows'); + cvals = A.vals(ia) .* B.vals(ib); + C = sptensor(csubs, cvals, size(A)); + return; + case {'tensor'} + csubs = A.subs; + cvals = A.vals .* B(csubs); + C = sptensor(csubs, cvals, size(A)); + return; + case {'ktensor'} + csubs = A.subs; + cvals = zeros(size(A.vals)); + R = numel(B.lambda); + N = ndims(A); + for r = 1:R + tvals = B.lambda(r) * A.vals; + for n = 1:N + v = B{n}(:,r); + tvals = tvals .* v(csubs(:,n)); + end + cvals = cvals + tvals; + end + C = sptensor(csubs, cvals, size(A)); + return; + otherwise + error('Invalid second argument for sptensor/times'); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/transpose.m b/external/tensor_toolbox_2.5/@sptensor/transpose.m new file mode 100755 index 0000000..6dcddd0 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/transpose.m @@ -0,0 +1,18 @@ +function transpose(x) +%TRANSPOSE is not defined on sparse tensors. +% +% See also SPTENSOR/PERMUTE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +error('Transpose on sparse tensor is not defined'); diff --git a/external/tensor_toolbox_2.5/@sptensor/ttm.m b/external/tensor_toolbox_2.5/@sptensor/ttm.m new file mode 100755 index 0000000..39ff64b --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/ttm.m @@ -0,0 +1,134 @@ +function Y = ttm(X,V,varargin) +%TTM Sparse tensor times matrix. +% +% Y = TTM(X,A,N) computes the n-mode product of the sptensor X with +% a dense matrix A; i.e., X x_N A. The integer N specifies the +% dimension (or mode) of X along which A should be multiplied. If +% size(A) = [J,I], then X must have size(X,N) = I. The result will +% will be a (dense) tensor or sptensor of the same order and size as X +% except that size(Y,N) = J. +% +% Y = TTM(X,{A,B,C,...}) computes the n-mode product of the sptensor +% X with a sequence of matrices in the cell array. The n-mode +% products are computed sequentially along all dimensions (or modes) +% of X. The cell array contains ndims(X) matrices. +% +% Y = TTM(X,{A,B,C,...},DIMS) computes the sequence tensor-matrix +% products along the dimensions specified by DIMS. +% +% Y = TTM(...,'t') performs the same computations as above except +% the matrices are transposed. +% +% Examples +% X = sptenrand([5 3 4 2], 10); +% A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2); +% Y = ttm(X, A, 1) %<-- computes X times A in mode-1 +% Y = ttm(X, {A,B,C,D}, 1) %<-- same as above +% Y = ttm(X, A', 1, 't') %<-- same as above +% Y = ttm(X, {A,B,C,D}, [1 2 3 4]) %<-- 4-way multiply +% Y = ttm(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above +% Y = ttm(X, {A,B,C,D}) %<-- same as above +% Y = ttm(X, {A',B',C',D'}, 't') %<-- same as above +% Y = ttm(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4 +% Y = ttm(X, {A,B,C,D}, [3 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, [1 2 4]) %<-- 3-way multiply +% Y = ttm(X, {A,B,C,D}, [1 2 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, -3) %<-- same as above +% Y = ttm(X, {A,B,C,D}, -3) %<-- same as above +% +% See also SPTENSOR, TENSOR/TTM. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Check the number of arguments +if (nargin < 2) + error('TTM requires at least two arguments.'); +end + +%% Create 'n' and 'tflag' arguments from varargin +n = 1:ndims(X); +tflag = ''; +if numel(varargin) == 1 + if ischar(varargin{1}) + tflag = varargin{1}; + else + n = varargin{1}; + end +elseif numel(varargin) == 2 + n = varargin{1}; + tflag = varargin{2}; +end + +%% Handle cell array +if iscell(V) + % Copy n into dims + dims = n; + % Check that the dimensions are valid + [dims,vidx] = tt_dimscheck(dims,ndims(X),numel(V)); + % Calculate individual products + Y = ttm(X, V{vidx(1)}, dims(1), tflag); + for i = 2 : numel(dims) + Y = ttm(Y, V{vidx(i)}, dims(i), tflag); + end + % All done + return; +end + +%% Check the second argument +if ndims(V) ~= 2 + error('tensor/ttm: 2nd argument must be a matrix.'); +end + +%% Flip V is transposed +if tflag == 't' + V = V'; +end + +%% Check n +if numel(n) ~= 1 || (n < 0) || (n > ndims(X)) + error('Dimension N must be between 1 and NDIMS(X).'); +end + +%% Compute the product + +% Check that sizes match! +if size(X,n) ~= size(V,2) + error('Size mismatch on V'); +end + +% Compute the new size +siz = size(X); +siz(n) = size(V,1); + +% Compute Xn' +Xnt = sptenmat(X,n,'t'); + +% Extract the dimensions +rdims = Xnt.rdims; +cdims = Xnt.cdims; + +% Convert to sparse matrix and do the multiplication; result is generally a +% dense matrix +Z = double(Xnt) * V'; + +if nnz(Z) <= 0.5 * prod(siz) + % Final result is a *sparse* tensor + Ynt = sptenmat(Z, rdims, cdims, siz); + Y = sptensor(Ynt); +else + % Final result is a *dense* tensor + Ynt = tenmat(Z, rdims, cdims, siz); + Y = tensor(Ynt); +end + +end diff --git a/external/tensor_toolbox_2.5/@sptensor/ttt.m b/external/tensor_toolbox_2.5/@sptensor/ttt.m new file mode 100755 index 0000000..4a1cc84 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/ttt.m @@ -0,0 +1,171 @@ +function c = ttt(varargin) +%TTT Sparse tensor times sparse tensor. +% +% Z = TTT(X,Y) computes the outer product of tensors X and Y. +% +% Z = TTT(X,Y,XDIMS,YDIMS) computes the contracted product of +% tensors X and Y in the dimensions specified by the row vectors +% XDIMS and YDIMS. The sizes of the dimensions specified by XDIMS +% and YDIMS must match; that is, size(X,XDIMS) must equal +% size(Y,YDIMS). +% +% Z = TTT(X,Y,DIMS) computes the inner product of tensors X and Y in +% the dimensions specified by the vector DIMS. The sizes of the +% dimensions specified by DIMS must match; that is, size(X,DIMS) +% must equal size(Y,DIMS). +% +% In all cases, the result Z is a sparse tensor if it has 50% or +% fewer nonzeros; otherwise ther result is returned as a dense +% tensor. +% +% Examples +% X = sptenrand([4 2 3], 10); +% Y = sptenrand([3 4 2], 10); +% Z = ttt(X,Y) %<-- outer product of X and Y +% Z = ttt(X,X,1:3) %<-- inner product of X with itself +% Z = ttt(X,Y,[1 2 3],[2 3 1]) %<-- inner product of X & Y +% Z = ttt(X,Y,[1 3],[2 1]) %<-- product of X & Y along specified dims +% +% See also SPTENSOR, TENSOR/TTT, SPTENSOR/TTV, SPTENSOR/TTM. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +%%%%%%%%%%%%%%%%%%%%%% +%%% ERROR CHECKING %%% +%%%%%%%%%%%%%%%%%%%%%% + +% Check the number of arguments +if (nargin < 2) + error('TTT requires at least two arguments.'); +end + +% Check the first argument +if ~isa(varargin{1}, 'sptensor') + error('First argument must be a sptensor.'); +else + a = varargin{1}; +end + +% Check the second argument +if ~isa(varargin{2}, 'sptensor') + error('Second argument must be a sptensor.'); +else + b = varargin{2}; +end + +% Optional 3rd argument +if nargin >= 3 + adims = varargin{3}; +else + adims = []; +end + +% Optional 4th argument +if nargin >= 4 + bdims = varargin{4}; +else + bdims = adims; +end + +if ~isempty(adims) + tt_dimscheck(adims,ndims(a)); +end +if ~isempty(bdims) + tt_dimscheck(bdims,ndims(b)); +end + +asiz = size(a); +bsiz = size(b); +if ~isequal(asiz(adims),bsiz(bdims)) + error('Specified dimensions do not match.'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% COMPUTE THE PRODUCT %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Remaining dimensions +aremdims = setdiff(1:ndims(a),adims); +bremdims = setdiff(1:ndims(b),bdims); + +if (nnz(a) == 0) || (nnz(b) == 0) + if isempty(aremdims) && isempty(bremdims) + c = 0; + else + c = sptensor([],[],[a.size(aremdims) b.size(bremdims)]); + end + return; +end + +if isempty(adims) && isempty(bdims) + aii = ones(nnz(a),1); + bii = ones(nnz(b),1); + m = 1; +else + innersubs = [a.subs(:,adims); b.subs(:,bdims)]; + [junk1,junk2,loc] = unique(innersubs,'rows'); + aii = loc(1:nnz(a)); + bii = loc(nnz(a)+1:end); + m = length(junk2); +end + +if isempty(aremdims) + ajj = ones(nnz(a),1); + asubs = []; + n = 1; +else + [asubs,junk,ajj] = unique(a.subs(:,aremdims),'rows'); + n = length(junk); +end +if isempty(bremdims) + bjj = ones(nnz(b),1); + bsubs = []; + p = 1; +else + [bsubs,junk,bjj] = unique(b.subs(:,bremdims),'rows'); + p = length(junk); +end + +aa = sparse(aii,ajj,a.vals,m,n); +bb = sparse(bii,bjj,b.vals,m,p); +cc = aa'*bb; + +% Check for a scalar result, corresponding to an inner product. +if isempty(aremdims) && isempty(bremdims) + c = sum(nonzeros(cc)); + return; +end + +% If cc is a row vector, then transpose to work as a column vector +% (otherwise 'find' returns row vectors) +if size(cc,1) == 1 + [jj,ii,newvals] = find(cc'); +else + [ii,jj,newvals] = find(cc); +end + +if isempty(asubs) && ~isempty(bsubs) + newsubs = bsubs(jj,:); +elseif ~isempty(asubs) && isempty(bsubs) + newsubs = asubs(ii,:); +else + newsubs = [asubs(ii,:), bsubs(jj,:)]; +end + +c = sptensor(newsubs,newvals,[a.size(aremdims) b.size(bremdims)]); + +% Convert the result to dense if it has more than 50% nonzeros. +if nnz(c) > 0.5 * prod(c.size) + c = tensor(c); +end diff --git a/external/tensor_toolbox_2.5/@sptensor/ttv.m b/external/tensor_toolbox_2.5/@sptensor/ttv.m new file mode 100755 index 0000000..fc6ce37 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/ttv.m @@ -0,0 +1,104 @@ +function c = ttv(a,v,dims) +%TTV Sparse tensor times vector. +% +% Y = TTV(X,V,N) computes the product of a sparse tensor X with a +% (column) vector V. The integer N specifies the dimension in X +% along which V is multiplied. If size(V) = [I,1], then X must have +% size(X,N) = I. Note that ndims(Y) = ndims(X) - 1 because the N-th +% dimension is removed. +% +% Y = TTV(X,U) computes the product of a sparse tensor X with a +% sequence of vectors in the cell array U. The products are +% computed sequentially along all dimensions (or modes) of X. The +% cell array U contains ndims(X) vectors. +% +% Y = TTV(X,U,DIMS) computes the sequence tensor-vector products +% along the dimensions specified by DIMS. +% +% In all cases, the result Y is a sparse tensor if it has 50% or +% fewer nonzeros; otherwise ther result is returned as a dense +% tensor. +% +% See also SPTENSOR, SPTENSOR/TTM, TENSOR, TENSOR/TTV. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Check the number of arguments +if (nargin < 2) + error('TTV requires at least two arguments.'); +end + +% Check for 3rd argument +if ~exist('dims','var') + dims = []; +end + +% Check that 2nd argument is cell array. If not, recall with v as a +% cell array with one element. +if ~iscell(v) + c = ttv(a,{v},dims); + return; +end + +% Get sorted dims and index for multiplicands +[dims,vidx] = tt_dimscheck(dims,ndims(a),numel(v)); +remdims = setdiff(1:ndims(a),dims); + +% Check that each multiplicand is the right size. +for i = 1:numel(dims) + if ~isequal(size(v{vidx(i)}),[size(a,dims(i)) 1]) + error('Multiplicand is wrong size'); + end +end + +% Multiply each value by the appropriate elements of the +% appropriate vector +newvals = a.vals; +subs = a.subs; +for n = 1:length(dims) + idx = subs(:,dims(n)); % extract indices for dimension n + w = v{vidx(n)}; % extract nth vector + bigw = w(idx); % stretch out the vector + newvals = newvals .* bigw; +end + +% Case 0: If all dimensions were used, then just return the sum +if isempty(remdims) + c = sum(newvals); + return; +end + +% Otherwise, figure out the subscripts and accumuate the results. +newsubs = a.subs(:,remdims); +newsiz = a.size(remdims); + +% Case I: Result is a vector +if numel(remdims) == 1 + c = accumarray(newsubs,newvals,[newsiz 1]); + if nnz(c) <= 0.5 * newsiz + c = sptensor((1:newsiz)',c,newsiz); + else + c = tensor(c,newsiz); + end + return; +end + +% Case II: Result is a multiway array +c = sptensor(newsubs, newvals, newsiz); + +% Convert to a dense tensor if more than 50% of the result is nonzero. +if nnz(c) > 0.5 * prod(c.size) + c = tensor(c); +end + +return; diff --git a/external/tensor_toolbox_2.5/@sptensor/uminus.m b/external/tensor_toolbox_2.5/@sptensor/uminus.m new file mode 100755 index 0000000..f6ee369 --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/uminus.m @@ -0,0 +1,18 @@ +function t = uminus(t) +%UMINUS Unary minus (-) for sptensor. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +t.vals = -t.vals; diff --git a/external/tensor_toolbox_2.5/@sptensor/uplus.m b/external/tensor_toolbox_2.5/@sptensor/uplus.m new file mode 100755 index 0000000..ff217dc --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/uplus.m @@ -0,0 +1,19 @@ +function t = uplus(t) +%UPLUS Unary plus (+) for sptensor. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% This function does nothing! + diff --git a/external/tensor_toolbox_2.5/@sptensor/xor.m b/external/tensor_toolbox_2.5/@sptensor/xor.m new file mode 100755 index 0000000..301fefa --- /dev/null +++ b/external/tensor_toolbox_2.5/@sptensor/xor.m @@ -0,0 +1,52 @@ +function C = xor(A,B) +%XOR Logical XOR for sptensors. +% +% See also SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Observations for sparse matrix case. +% The result of xor(a,5) is dense! +% The result of xor(a,0) is dense! +% The result of xor(a,full(a)) is dense! +% The result of xor(a,b) is sparse. + +%% Case 1: One argument is a scalar +if isscalar(B) || isa(B,'tensor') + C = xor(full(A),B); + return; +end +if isscalar(A) + C = xor(A,full(B)); + return; +end + + +%% Case 2: Both x and y are tensors of some sort +if ~isequal(size(A),size(B)) + error('Must be tensors of the same size'); +end + +if isa(A,'sptensor') && isa(B,'sptensor') + C = sptensor([A.subs; B.subs], 1, size(A), @(x) length(x) == 1); + return; +end + +if isa(B,'tensor') + Bsubs = find(B ~= 0); + C = sptensor([A.subs; Bsubs], 1, size(A), @(x) length(x) == 1); + return; +end + +%% Otherwise +error('The arguments must be two sptensors or an sptensor and a scalar.'); diff --git a/external/tensor_toolbox_2.5/@tenmat/Contents.m b/external/tensor_toolbox_2.5/@tenmat/Contents.m new file mode 100755 index 0000000..4b975b8 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/Contents.m @@ -0,0 +1,19 @@ +% @TENMAT +% +% Files +% ctranspose - Complex conjugate transpose for tenmat. +% disp - Command window display of a matricized tensor (tenmat). +% display - Command window display of a tenmat. +% double - Convert tenmat to double array. +% end - Last index of indexing expression for tenmat. +% minus - Binary subtraction (-) for tenmat. +% mtimes - Multiplies two tenmat objects. +% norm - Frobenius norm of a tenmat. +% plus - Binary addition (+) for tenmat. +% size - Size of tenmat. +% subsasgn - Subscripted assignment for tenmat. +% subsref - Subscripted reference for tenmat. +% tenmat - Create a matricized tensor. +% tsize - Tensor size of tenmat. +% uminus - Unary minus (-) for tenmat. +% uplus - Unary plus (+) for tenmat. diff --git a/external/tensor_toolbox_2.5/@tenmat/ctranspose.m b/external/tensor_toolbox_2.5/@tenmat/ctranspose.m new file mode 100755 index 0000000..9877efc --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/ctranspose.m @@ -0,0 +1,23 @@ +function a = ctranspose(a) +%CTRANSPOSE Complex conjugate transpose for tenmat. +% +% C = CTRANSPOSE(A) swaps the row and column indices of A. +% +% See also TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +tmp = a.rindices; +a.rindices = a.cindices; +a.cindices = tmp; +a.data = ctranspose(a.data); diff --git a/external/tensor_toolbox_2.5/@tenmat/disp.m b/external/tensor_toolbox_2.5/@tenmat/disp.m new file mode 100755 index 0000000..54f1e33 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/disp.m @@ -0,0 +1,41 @@ +function disp(t,name) +%DISP Command window display of a matricized tensor (tenmat). +% +% DISP(T) displays a tensor as matrix with no name. +% +% DISP(T,NAME) display a tensor as matrix with the given name. +% +% See also TENMAT, TENMAT/DISPLAY. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~exist('name','var') + name = 'ans'; +end + +fprintf('%s is a matrix corresponding to a tensor of size %s\n',... + name,tt_size2str(t.tsize)); +fprintf('\t%s.rindices = %s (modes of tensor corresponding to rows)\n',... + name,['[ ' num2str(t.rindices) ' ]']); +fprintf('\t%s.cindices = %s (modes of tensor corresponding to columns)\n',... + name,['[ ' num2str(t.cindices) ' ]']); + +if isempty(t.data) + fprintf('\t%s.data = []\n',name); +else + fprintf('\t%s.data = \n',name); + output = tt_matrix2cellstr(t.data); + fprintf('\t\t%s\n',output{:}); +end + + diff --git a/external/tensor_toolbox_2.5/@tenmat/display.m b/external/tensor_toolbox_2.5/@tenmat/display.m new file mode 100755 index 0000000..799759d --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/display.m @@ -0,0 +1,18 @@ +function display(t) +%DISPLAY Command window display of a tenmat. +% +% See also TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +disp(t,inputname(1)); diff --git a/external/tensor_toolbox_2.5/@tenmat/double.m b/external/tensor_toolbox_2.5/@tenmat/double.m new file mode 100755 index 0000000..85bea21 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/double.m @@ -0,0 +1,18 @@ +function a = double(t) +%DOUBLE Convert tenmat to double array. +% +% See also TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +a = t.data; diff --git a/external/tensor_toolbox_2.5/@tenmat/end.m b/external/tensor_toolbox_2.5/@tenmat/end.m new file mode 100755 index 0000000..88c360b --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/end.m @@ -0,0 +1,24 @@ +function e = end(X,k,n) +%END Last index of indexing expression for tenmat. +% +% The expression X(end,:) will call END(X,1,2) to determine +% the value of the first index. +% +% See also TENMAT, TENMAT/SUBSREF, END. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if n > ndims(X) + error('Subscript out of range.'); +end +e = size(X.data,k); diff --git a/external/tensor_toolbox_2.5/@tenmat/minus.m b/external/tensor_toolbox_2.5/@tenmat/minus.m new file mode 100755 index 0000000..c436e1f --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/minus.m @@ -0,0 +1,38 @@ +function Z = minus(X,Y) +%MINUS Binary subtraction (-) for tenmat. +% +% See also TENMAT, TENMAT/TENMATFUN. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +fun = @minus; + +% One argument is a scalar +if ((prod(size(X)) == 1 || prod(size(Y)) == 1)) + if (prod(size(Y)) == 1) && isa(X,'tenmat') + Z = X; + Z.data = fun(Z.data,Y); + else + Z = Y; + Z.data = fun(X,Z.data); + end + return; +end + + +% Both arguments are tenmats +Z = tenmat(Y); +if ~(isequal(size(Y),size(Z))) + error('Tenmat size mismatch.') +end +Z.data = fun(X.data,Z.data); diff --git a/external/tensor_toolbox_2.5/@tenmat/mtimes.m b/external/tensor_toolbox_2.5/@tenmat/mtimes.m new file mode 100755 index 0000000..82da32a --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/mtimes.m @@ -0,0 +1,62 @@ +function C = mtimes(A,B) +%MTIMES Multiplies two tenmat objects. +% +% C = MTIMES(A,B) computes the product of A and B. The result is a +% TENMAT object and can be transformed into a tensor. +% +% C = MTIMES(A,B) is called for the syntax 'A * B' when A or B is a +% TENMAT object. +% +% See also TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Handle scalar input +if ~isa(B,'tenmat') && numel(B) == 1 + C = A; + C.data = C.data * B; + return; +end +if ~isa(A,'tenmat') && numel(A) == 1 + C = B; + C.data = C.data * A; + return; +end + +% Handle matrix input +if ~isa(A,'tenmat') + A = tenmat(A,1); +end + +if ~isa(B,'tenmat') + B = tenmat(B,1); +end + +% Error check +if size(A,2) ~= size(B,1) + error(['Size mismatch: Number of columns in A is not equal to' ... + ' the number of rows in B']); +end + +tsiz = [A.tsize(A.rindices) B.tsize(B.cindices)]; + +if ~isempty(tsiz) + C = tenmat; + C.tsize = tsiz; + C.rindices = 1:length(A.rindices); + C.cindices = (1:length(B.cindices)) + length(A.rindices); + C.data = A.data * B.data; +else + C = A.data * B.data; +end + diff --git a/external/tensor_toolbox_2.5/@tenmat/norm.m b/external/tensor_toolbox_2.5/@tenmat/norm.m new file mode 100755 index 0000000..9b0414f --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/norm.m @@ -0,0 +1,21 @@ +function n = norm(T) +%NORM Frobenius norm of a tenmat. +% +% NORM(X) returns the Frobenius norm of a tenmat. +% +% See also TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +v = reshape(T.data, numel(T.data), 1); +n = norm(v); diff --git a/external/tensor_toolbox_2.5/@tenmat/plus.m b/external/tensor_toolbox_2.5/@tenmat/plus.m new file mode 100755 index 0000000..6348ab5 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/plus.m @@ -0,0 +1,38 @@ +function Z = plus(X,Y) +%PLUS Binary addition (+) for tenmat. +% +% See also TENMAT, TENMAT/TENMATFUN. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +fun = @plus; + +% One argument is a scalar +if ((prod(size(X)) == 1 || prod(size(Y)) == 1)) + if (prod(size(Y)) == 1) && isa(X,'tenmat') + Z = X; + Z.data = fun(Z.data,Y); + else + Z = Y; + Z.data = fun(X,Z.data); + end + return; +end + + +% Both arguments are tenmats +Z = tenmat(Y); +if ~(isequal(size(Y),size(Z))) + error('Tenmat size mismatch.') +end +Z.data = fun(X.data,Z.data); diff --git a/external/tensor_toolbox_2.5/@tenmat/size.m b/external/tensor_toolbox_2.5/@tenmat/size.m new file mode 100755 index 0000000..8007a88 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/size.m @@ -0,0 +1,31 @@ +function sz = size(a,idx) +%SIZE Size of tenmat. +% +% D = SIZE(X) returns the two-element row vector D = [M N] +% containing the number of rows and columns in the matrix. +% +% M = SIZE(X,DIM) returns the length of the dimension specified by +% the scalar DIM. For example, SIZE(X,1) returns the number of +% rows. +% +% See also TENMAT, TENMAT/TSIZE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(a.data) + sz = []; +elseif exist('idx', 'var') + sz = size(a.data, idx); +else + sz = size(a.data); +end diff --git a/external/tensor_toolbox_2.5/@tenmat/subsasgn.m b/external/tensor_toolbox_2.5/@tenmat/subsasgn.m new file mode 100755 index 0000000..3f01cfd --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/subsasgn.m @@ -0,0 +1,33 @@ +function t = subsasgn(t,s,b) +%SUBSASGN Subscripted assignment for tenmat. +% +% Examples +% X = tenmat(rand(3,4,2),1); +% X(1:2,1:2) = ones(2,2); <-- Calls SUBSASGN +% +% See also TENMAT, TENMAT/SUBSREF. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +switch s.type + case '()' + [m n] = size(t.data); + t.data(s.subs{:}) = b; + if ~isequal([m n],size(t.data)) + error('Ambiguous change in size') + end + otherwise + error('Invalid assignment for tenmat.') +end + + diff --git a/external/tensor_toolbox_2.5/@tenmat/subsref.m b/external/tensor_toolbox_2.5/@tenmat/subsref.m new file mode 100755 index 0000000..2daaf66 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/subsref.m @@ -0,0 +1,44 @@ +function a = subsref(t,s) +%SUBSREF Subscripted reference for tenmat. +% +% Examples +% X(i,j) <-- returns the (i,j) entry in X +% X.data <-- returns a 2D array of the data +% X.tsize <-- returns the size original tensor +% X.rdims <-- tensor dimensions that were mapped to rows +% X.cdims <-- tensor dimensions that were mapped to columns +% +% See also TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +switch s(1).type + case '.' + switch s(1).subs + case 'data' + a = tt_subsubsref(t.data,s); + case 'tsize' + a = tt_subsubsref(t.tsize,s); + case {'rindices','rdims'} + a = tt_subsubsref(t.rindices,s); + case {'cindices','cdims'} + a = tt_subsubsref(t.cindices,s); + otherwise + error(['No such field: ', s.subs]); + end + case '()' + a = t.data(s.subs{:}); + otherwise + error('Invalid subsref into tenmat.') +end +end diff --git a/external/tensor_toolbox_2.5/@tenmat/tenmat.m b/external/tensor_toolbox_2.5/@tenmat/tenmat.m new file mode 100755 index 0000000..489470e --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/tenmat.m @@ -0,0 +1,182 @@ +function A = tenmat(varargin) +%TENMAT Create a matricized tensor. +% +% A = TENMAT(T, RDIMS) creates a matrix representation of a tensor +% T. The dimensions (or modes) specified in RDIMS map to the rows +% of the matrix, and the remaining dimensions (in ascending order) +% map to the columns. +% +% A = TENMAT(T, CDIMS, 't') does the same as above, but instead the +% column dimensions are specified, and the remaining dimensions (in +% ascending order) map to the rows. +% +% A = TENMAT(T, RDIMS, CDIMS) creates a matrix representation of +% tensor T. The dimensions specified in RDIMS map to the rows of +% the matrix, and the dimensions specified in CDIMS map to the +% columns, in the order given. +% +% A = TENMAT(T, RDIM, STR) creates the same matrix representation as +% above, except only one dimension in RDIM maps to the rows of the +% matrix, and the remaining dimensions span the columns in an order +% specified by the string argument STR as follows: +% +% 'fc' - Forward cyclic. Order the remaining dimensions in the +% columns by [RDIM+1:ndims(T), 1:RDIM-1]. This is the +% ordering defined by Kiers. +% +% 'bc' - Backward cyclic. Order the remaining dimensions in the +% columns by [RDIM-1:-1:1, ndims(T):-1:RDIM+1]. This is the +% ordering defined by De Lathauwer, De Moor, and Vandewalle. +% +% A = TENMAT(A, RDIMS, CDIMS, TSIZE) creates a tenmat from a matrix +% A along with the mappings of the row (RDIMS) and column indices +% (CDIMS) and the size of the original tensor (TSIZE). +% +% A = TENMAT(B) is the copy constructor for B also a tenmat. +% +% A = TENMAT is the empty constructor. +% +% See also TENSOR, SPTENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +% +% Includes improvements offered by Marcus Brubaker. + + +%---------- +% Case 0a: Empty Contructor +%---------- +if (nargin == 0) + A.tsize = []; + A.rindices = []; + A.cindices = []; + A.data = []; + A = class(A, 'tenmat'); + return; +end + +%---------- +% Case 0b: Copy Contructor +%---------- +if (nargin == 1) + B = varargin{1}; + A.tsize = B.tsize; + A.rindices = B.rindices; + A.cindices = B.cindices; + A.data = B.data; + A = class(A, 'tenmat'); + return; +end + +%---------- +% Case I: Called to convert a matrix to a tenmat +%---------- +if (nargin == 4) + + data = varargin{1}; + if ~isnumeric(data) || (ndims(data) ~= 2) + error('A must be a matrix.'); + end + rdims = varargin{2}; + cdims = varargin{3}; + tsize = varargin{4}; + + % Error check + n = numel(tsize); + if ~isequal(1:n, sort([rdims cdims])) + error('Incorrect specification of dimensions'); + elseif (prod(tsize(rdims)) ~= size(data,1)) + error('SIZE(A,1) does not match size specified by RDIMS and SIZE.'); + elseif (prod(tsize(cdims)) ~= size(data,2)) + error('SIZE(A,2) does not match size specified by CDIMS and SIZE.'); + end + + % Save class variables + A.tsize = tsize; + A.rindices = rdims; + A.cindices = cdims; + A.data = data; + A = class(A, 'tenmat'); + return; + +end + +%---------- +% Case II: Called to convert an MDA to a tenmat --- recall after +% converting MDA to a tensor. +%---------- +if isa(varargin{1},'double') + A = tenmat(tensor(varargin{1}),varargin{2:nargin}); + return; +end + +%---------- +% Case III: Convert a tensor to a tenmat +%---------- + +if (nargin < 2) || (nargin > 3) + error('Incorrect number of arguments.'); +end + +% Save the size of T and the number of dimensions +T = varargin{1}; +tsize = size(T); +n = ndims(T); + +% Figure out which dimensions get mapped where +if (nargin == 2) + rdims = varargin{2}; + tmp = true(1,n); + tmp(rdims) = false; + cdims = find(tmp); % i.e., cdims = setdiff(1:n, rdims); +elseif isa(varargin{3},'char') + switch varargin{3} + case 't' % Transpose + cdims = varargin{2}; + tmp = true(1,n); + tmp(cdims) = false; + rdims = find(tmp); % i.e., rdims = setdiff(1:n, cdims); + case 'fc' % Forward cyclic + rdims = varargin{2}; + if (numel(rdims) ~= 1) + error('Only one row dimension if third argument is ''fc''.'); + end + cdims = [rdims+1:n, 1:rdims-1]; + case 'bc' % Backward cyclic + rdims = varargin{2}; + if (numel(rdims) ~= 1) + error('Only one row dimension if third argument is ''bc''.'); + end + cdims = [rdims-1:-1:1, n:-1:rdims+1]; + otherwise + error('Unrecognized option'); + end +else + rdims = varargin{2}; + cdims = varargin{3}; +end + +% Error check +if ~isequal(1:n, sort([rdims cdims])) + error('Incorrect specification of dimensions'); +end + +% Permute T so that the dimensions specified by RDIMS come first +data = reshape(double(permute(T,[rdims cdims])), prod(tsize(rdims)), prod(tsize(cdims))); + +% Save class variables +A.tsize = tsize; +A.rindices = rdims; +A.cindices = cdims; +A.data = data; +A = class(A, 'tenmat'); diff --git a/external/tensor_toolbox_2.5/@tenmat/tsize.m b/external/tensor_toolbox_2.5/@tenmat/tsize.m new file mode 100755 index 0000000..15569ff --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/tsize.m @@ -0,0 +1,33 @@ +function sz = tsize(a,idx) +%TSIZE Tensor size of tenmat. +% +% D = TSIZE(X) returns the size of the tensor being stored as a +% matrix. +% +% M = TSIZE(X,DIM) returns the length of the dimension(s) specified +% by DIM. For example, SIZE(X,1) returns the size of the first +% dimension of the tensor. +% +% See also TENMAT, TENMAT/SIZE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(a.data) + sz = []; +elseif exist('idx', 'var') + sz = a.tsize(idx); +else + sz = a.tsize; +end + +return; diff --git a/external/tensor_toolbox_2.5/@tenmat/uminus.m b/external/tensor_toolbox_2.5/@tenmat/uminus.m new file mode 100755 index 0000000..18a7197 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/uminus.m @@ -0,0 +1,18 @@ +function t = uminus(t) +%UMINUS Unary minus (-) for tenmat. +% +% See also TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +t.data = -t.data; diff --git a/external/tensor_toolbox_2.5/@tenmat/uplus.m b/external/tensor_toolbox_2.5/@tenmat/uplus.m new file mode 100755 index 0000000..7f799f7 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tenmat/uplus.m @@ -0,0 +1,19 @@ +function t = uplus(t) +%UPLUS Unary plus (+) for tenmat. +% +% See also TENMAT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% This function does nothing! + diff --git a/external/tensor_toolbox_2.5/@tensor/Contents.m b/external/tensor_toolbox_2.5/@tensor/Contents.m new file mode 100755 index 0000000..ce77bec --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/Contents.m @@ -0,0 +1,56 @@ +% @TENSOR +% +% Files +% and - Logical AND (&) for tensors. +% collapse - Collapse tensor along specified dimensions. +% contract - Contract tensor along two dimensions (array trace). +% ctranspose - is not defined for tensors. +% disp - Command window display of a tensor. +% display - Command window display of a tensor. +% double - Convert tensor to double array. +% end - Last index of indexing expression for tensor. +% eq - Equal (==) for tensors. +% find - Find subscripts of nonzero elements in a tensor. +% full - Convert to a (dense) tensor. +% ge - Greater than or equal (>=) for tensors. +% gt - Greater than (>) for tensors. +% innerprod - Efficient inner product with a tensor. +% isequal - for tensors. +% issymmetric - Verify that a tensor X is symmetric in specified modes. +% ldivide - Left array divide for tensor. +% le - Less than or equal (<=) for tensor. +% lt - Less than (<) for tensor. +% minus - Binary subtraction (-) for tensors. +% mldivide - Slash left division for tensors. +% mrdivide - Slash right division for tensors. +% mtimes - tensor-scalar multiplication. +% mttkrp - Matricized tensor times Khatri-Rao product for tensor. +% ndims - Return the number of dimensions of a tensor. +% ne - Not equal (~=) for tensors. +% nnz - Number of nonzeros for tensors. +% norm - Frobenius norm of a tensor. +% not - Logical NOT (~) for tensors. +% nvecs - Compute the leading mode-n vectors for a tensor. +% or - Logical OR (|) for tensors. +% permute - Permute tensor dimensions. +% plus - Binary addition (+) for tensors. +% power - Elementwise power (.^) operator for a tensor. +% rdivide - Right array divide for tensors. +% reshape - Change tensor size. +% scale - Scale along specified dimensions of tensor. +% size - Tensor dimensions. +% squeeze - Remove singleton dimensions from a tensor. +% subsasgn - Subscripted assignment for a tensor. +% subsref - Subscripted reference for tensors. +% symmetrize - Symmetrize a tensor X in specified modes. +% tenfun - Apply a function to each element in a tensor. +% tensor - Create tensor. +% times - Array multiplication for tensors. +% transpose - is not defined on tensors. +% ttm - Tensor times matrix. +% ttsv - Tensor times same vector in multiple modes. +% ttt - Tensor mulitplication (tensor times tensor). +% ttv - Tensor times vector. +% uminus - Unary minus (-) for tensors. +% uplus - Unary plus (+) for tensors. +% xor - Logical EXCLUSIVE OR for tensors. diff --git a/external/tensor_toolbox_2.5/@tensor/and.m b/external/tensor_toolbox_2.5/@tensor/and.m new file mode 100755 index 0000000..4f5c75c --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/and.m @@ -0,0 +1,18 @@ +function Z = and(X,Y) +%AND Logical AND (&) for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@and,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/collapse.m b/external/tensor_toolbox_2.5/@tensor/collapse.m new file mode 100755 index 0000000..32bd2de --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/collapse.m @@ -0,0 +1,76 @@ +function Y = collapse(X,dims,fun) +%COLLAPSE Collapse tensor along specified dimensions. +% +% Y = COLLAPSE(X,DIMS) sums the entries of X along all dimensions +% specified in DIMS. If DIMS is negative, then X is summed across +% all dimensions *not* specified by -DIMS. +% +% Y = COLLAPSE(X) is shorthand for S = COLLAPSE(X,1:ndims(X)). +% +% Y = COLLAPSE(X,DIMS,FUN) accumulates the entries of T using the +% accumulation function @FUN. +% +% Examples +% X = tenrand([4 4 4]); +% Y = collapse(X,[2 3]) %<-- sum of entries in each mode-1 slice +% Y = collapse(X,[1 2],@max) %<-- max entry in each mode-3 slice +% +% See also TENSOR, TENSOR/SCALE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(X.data) + Y = []; + return; +end + +if ~exist('dims', 'var') + dims = 1:ndims(X); +end + +if isempty(dims) + Y = X; + return; +end + +if ~exist('fun', 'var') + fun = @sum; +end + +dims = tt_dimscheck(dims,ndims(X)); +remdims = setdiff(1:ndims(X),dims); + +% Check for the case where we accumulate over *all* dimensions +if isempty(remdims) + Y = fun(X.data(:)); + return; +end + +% Calculate the size of the result +newsiz = size(X,remdims); + +% Convert to a matrix where each row is going to be collapsed +A = double(tenmat(X,remdims,dims)); + +% Apply the collapse function +B = zeros(size(A,1),1); +for i = 1:size(A,1) + B(i) = fun(A(i,:)); +end + +% Form and return the final result +Y = tensor(tenmat(B,1:numel(remdims),[],newsiz)); + + + + diff --git a/external/tensor_toolbox_2.5/@tensor/contract.m b/external/tensor_toolbox_2.5/@tensor/contract.m new file mode 100755 index 0000000..105b5f7 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/contract.m @@ -0,0 +1,75 @@ +function y = contract(x,i,j) +%CONTRACT Contract tensor along two dimensions (array trace). +% +% Y = CONTRACT(X,I,J) contracts the entries of X along dimensions I +% and J. Contraction is a generalization of matrix trace. In other +% words, the trace is performed along the two-dimensional slices +% defined by dimensions I and J. It is possible to implement tensor +% multiplication as an outer product followed by a contraction. +% +% Examples +% X = tensor(rand(4,3,2)); Y = tensor(rand(3,2,4)); +% Z1 = ttt(X,Y,1,3); %<-- Normal tensor multiplication +% Z2 = contract(ttt(X,Y),1,6); %<-- Outer product + contract +% norm(Z1-Z2) %<-- Should be zero +% +% See also TENSOR, TENSOR/TTT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Error checking +if x.size(i) ~= x.size(j) + error('Must contract along equally sized dimensions'); +end + +% Error checking +if i == j + error('Must contract along two different dimensions'); +end + +% Easy case - returns a scalar +if ndims(x) == 2 + y = trace(x.data); + return; +end + +% Remaining dimensions after trace +remdims = setdiff(1:ndims(x),[i j]); + +% Size for y +newsize = x.size(remdims); + +% Total size of remainder +m = prod(newsize); + +% Number of items to add for trace +n = x.size(i); + +% Permute trace dimensions to the end +x = permute(x, [remdims i j]); + +% Reshape data to be 3D +data = reshape(x.data, m, n, n); + +% Add diagonal entries for each slice +newdata = zeros(m,1); +for i = 1:n + newdata = newdata + data(:,i,i); +end + +% Reshape result +if numel(newsize) > 1 + newdata = reshape(newdata,newsize); +end +y = tensor(newdata,newsize); + diff --git a/external/tensor_toolbox_2.5/@tensor/ctranspose.m b/external/tensor_toolbox_2.5/@tensor/ctranspose.m new file mode 100755 index 0000000..ccf44b0 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/ctranspose.m @@ -0,0 +1,18 @@ +function ctranspose(x) +%CTRANSPOSE is not defined for tensors. +% +% See also TENSOR/PERMUTE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +error('Transpose on tensor is not defined'); diff --git a/external/tensor_toolbox_2.5/@tensor/disp.m b/external/tensor_toolbox_2.5/@tensor/disp.m new file mode 100755 index 0000000..63b9c67 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/disp.m @@ -0,0 +1,50 @@ +function disp(X,name) +%DISP Command window display of a tensor. +% +% DISP(X) displays a tensor with no name. +% +% DISP(X,NAME) displays a tensor with the given name. +% +% See also TENSOR, TENSOR/DISPLAY. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~exist('name','var') + name = 'ans'; +end + +fprintf(1,'%s is a tensor of size %s\n',name,tt_size2str(X.size)); + +if isempty(X.data) + fprintf(1,'\t%s = []\n',name); +end + +s = shiftdim(num2cell(X.data,1:2),2); + +for i = 1:numel(s) + fprintf('\t%s',name); + if ndims(X) == 1 + fprintf('(:)'); + elseif ndims(X) == 2 + fprintf('(:,:)'); + elseif ndims(X) > 2 + fprintf('(:,:'); + fprintf(',%d',tt_ind2sub(X.size(3:end),i)); + fprintf(')'); + end + fprintf(' = \n'); + output = tt_matrix2cellstr(s{i}); + fprintf('\t%s\n',output{:}); +end + +end diff --git a/external/tensor_toolbox_2.5/@tensor/display.m b/external/tensor_toolbox_2.5/@tensor/display.m new file mode 100755 index 0000000..f561a4b --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/display.m @@ -0,0 +1,20 @@ +function display(t) +%DISPLAY Command window display of a tensor. +% +% DISPLAY(X) displays a tensor with its name. +% +% See also TENSOR, TENSOR/DISP. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +disp(t,inputname(1)); diff --git a/external/tensor_toolbox_2.5/@tensor/double.m b/external/tensor_toolbox_2.5/@tensor/double.m new file mode 100755 index 0000000..0e152d5 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/double.m @@ -0,0 +1,20 @@ +function A = double(X) +%DOUBLE Convert tensor to double array. +% +% A = double(X) converts X to a standard multidimensional array. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +A = double(X.data); diff --git a/external/tensor_toolbox_2.5/@tensor/end.m b/external/tensor_toolbox_2.5/@tensor/end.m new file mode 100755 index 0000000..7323bbc --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/end.m @@ -0,0 +1,24 @@ +function e = end(X,k,n) +%END Last index of indexing expression for tensor. +% +% The expression X(end,:,:) will call END(X,1,3) to determine +% the value of the first index. +% +% See also TENSOR, TENSOR/SUBSREF, END. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if n > ndims(X) + error('Subscript out of range.'); +end +e = X.size(k); diff --git a/external/tensor_toolbox_2.5/@tensor/eq.m b/external/tensor_toolbox_2.5/@tensor/eq.m new file mode 100755 index 0000000..682966b --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/eq.m @@ -0,0 +1,18 @@ +function Z = eq(X,Y) +%EQ Equal (==) for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@eq,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/find.m b/external/tensor_toolbox_2.5/@tensor/find.m new file mode 100755 index 0000000..071bbea --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/find.m @@ -0,0 +1,40 @@ +function [subs,vals] = find(t) +%FIND Find subscripts of nonzero elements in a tensor. +% +% S = FIND(X) returns the subscripts of the nonzero values in X. +% +% [S,V] = FIND(X) also returns a column vector of the values. +% +% Examples: +% X = tensor(rand(3,4,2)); +% subs = find(X > 0.5) %<-- find subscripts of values greater than 0.5 +% vals = X(subs) %<-- extract the actual values +% +% See also TENSOR/SUBSREF, TENSOR/SUBSASGN +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Find the *linear* indices of the nonzero elements +idx = find(t.data); + +% Convert the linear indices to subscripts +subs = tt_ind2sub(t.size,idx); + +% Extract the corresponding values and return as a column vector +if nargout > 1 + if isempty(subs) + vals = []; + else + vals = reshape(t.data(idx), length(idx), 1); + end +end diff --git a/external/tensor_toolbox_2.5/@tensor/full.m b/external/tensor_toolbox_2.5/@tensor/full.m new file mode 100755 index 0000000..cc87f3b --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/full.m @@ -0,0 +1,20 @@ +function X = full(X) +%FULL Convert to a (dense) tensor. +% +% FULL(X) returns X, i.e., does nothing. +% +% See also SPTENSOR/FULL, KTENSOR/FULL, TTENSOR/FULL. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +return; diff --git a/external/tensor_toolbox_2.5/@tensor/ge.m b/external/tensor_toolbox_2.5/@tensor/ge.m new file mode 100755 index 0000000..38887a2 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/ge.m @@ -0,0 +1,18 @@ +function Z = ge(X,Y) +%GE Greater than or equal (>=) for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@ge,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/gt.m b/external/tensor_toolbox_2.5/@tensor/gt.m new file mode 100755 index 0000000..8fd992f --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/gt.m @@ -0,0 +1,18 @@ +function Z = gt(X,Y) +%GT Greater than (>) for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@gt,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/innerprod.m b/external/tensor_toolbox_2.5/@tensor/innerprod.m new file mode 100755 index 0000000..5cc5938 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/innerprod.m @@ -0,0 +1,42 @@ +function res = innerprod(X,Y) +%INNERPROD Efficient inner product with a tensor. +% +% R = INNERPROD(X,Y) efficiently computes the inner product between +% two tensors X and Y. If Y is a tensor, then inner product is +% computed directly. Otherwise, the inner product method for +% that type of tensor is called. +% +% See also TENSOR, SPTENSOR/INNERPROD, KTENSOR/INNERPROD, TTENSOR/INNERPROD +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% X is a tensor +switch class(Y) + + case {'tensor'} + % No need for same size check because it is implicit in the inner + % product below. + x = reshape(X.data, 1, numel(X.data)); + y = reshape(Y.data, numel(Y.data), 1); + res = x*y; + + case {'sptensor','ktensor','ttensor'} + % Reverse arguments to call specialized code + res = innerprod(Y,X); + + otherwise + disp(['Inner product not available for class ' class(Y)]); + +end + +return; diff --git a/external/tensor_toolbox_2.5/@tensor/isequal.m b/external/tensor_toolbox_2.5/@tensor/isequal.m new file mode 100755 index 0000000..50ce39c --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/isequal.m @@ -0,0 +1,29 @@ +function z = isequal(x,y) +%ISEQUAL for tensors. +% +% ISEQUAL(A,B) compares the tensors A and B for equality. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% +if ~isequal(x.size,y.size) + z = false; +elseif isa(x,'tensor') && isa(y,'tensor') + z = isequal(x.data,y.data); +elseif isa(y,'sptensor') + z = isequal(x,full(y)); +else + z = false; +end diff --git a/external/tensor_toolbox_2.5/@tensor/issymmetric.m b/external/tensor_toolbox_2.5/@tensor/issymmetric.m new file mode 100755 index 0000000..ed02892 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/issymmetric.m @@ -0,0 +1,88 @@ +function [tf,all_diffs,all_perms] = issymmetric(X,grps) +%ISSYMMETRIC Verify that a tensor X is symmetric in specified modes. +% +% TF = ISSYMMETRIC(X) returns true if X is exactly symmetric for every +% permutation. +% +% [TF,DIFFS,PERMS] = ISSYMMETRIC(X) also returns that maximum difference +% in DIFFS for each permutation in PERMS (one permutation per row). +% +% [...] = ISSYMMETRIC(X,IDX) checks symmetry with respect to the modes +% specified in IDX, which can be an array of indices or a cell array of +% arrays of symmetric indices. +% +% See also SYMMETRIZE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +%T. Kolda, April 2011. + +n = ndims(X); +sz = size(X); + +% Check that grps exists; if not, create it. +if ~exist('grps','var') + grps = {1:n}; +end + +% Check that grps is a cell array. +if ~iscell(grps) + grps = {grps}; +end + +% Check tensor dimensions for compatibility with symmetrization +for i = 1:length(grps) + dims = grps{i}; + for j = dims(2:end) + if sz(j) ~= sz(dims(1)) + tf = false; + return; + end + end +end + +% Check actual symmetry +cnt = sum(cellfun(@(x) factorial(length(x)), grps)); +all_diffs = zeros(cnt,1); +all_perms = zeros(cnt,n); +idx = 1; +for i = 1:length(grps) + + % Compute the permutations for this group of symmetries + p = perms(grps{i}); + + for j = 1:size(p,1) + + % Create the permutation to check + q = 1:n; + q(grps{i}) = p(j,:); + + % Save the permutation + all_perms(idx,:) = q; + + % Do the permutation and see if it's a match. If it's not a match, + % record the difference. + Y = permute(X,q); + if isequal(X.data,Y.data) + all_diffs(idx) = 0; + else + all_diffs(idx) = max(abs(X.data(:)-Y.data(:))); + end + + % Increment the index + idx = idx + 1; + + end + +end + +tf = all(all_diffs == 0); diff --git a/external/tensor_toolbox_2.5/@tensor/ldivide.m b/external/tensor_toolbox_2.5/@tensor/ldivide.m new file mode 100755 index 0000000..9db0c93 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/ldivide.m @@ -0,0 +1,26 @@ +function Z = ldivide(X,Y) +%LDIVIDE Left array divide for tensor. +% +% LDIVIDE(A,B) is called for the syntax 'A .\ B' when A or B is a tensor. +% A and B must have the same size, unless one is a scalar. +% +% Examples +% X = tenrand([4 3 2],5); +% X .\ 3 +% X .\ X +% +% See also TENSOR, TENSOR/RDIVIDE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@ldivide,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/le.m b/external/tensor_toolbox_2.5/@tensor/le.m new file mode 100755 index 0000000..3968cac --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/le.m @@ -0,0 +1,18 @@ +function Z = le(X,Y) +%LE Less than or equal (<=) for tensor. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@le,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/lt.m b/external/tensor_toolbox_2.5/@tensor/lt.m new file mode 100755 index 0000000..99bb188 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/lt.m @@ -0,0 +1,18 @@ +function Z = lt(X,Y) +%LT Less than (<) for tensor. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@lt,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/minus.m b/external/tensor_toolbox_2.5/@tensor/minus.m new file mode 100755 index 0000000..2541b2e --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/minus.m @@ -0,0 +1,22 @@ +function Z = minus(X,Y) +%MINUS Binary subtraction (-) for tensors. +% +% MINUS(A,B) is called for the syntax 'A - B' when A or B is a tensor. A +% and B must have the same size, unless one is a scalar. A scalar can be +% subtracted from a tensor of any size. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@minus,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/mldivide.m b/external/tensor_toolbox_2.5/@tensor/mldivide.m new file mode 100755 index 0000000..4cdc59e --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/mldivide.m @@ -0,0 +1,31 @@ +function Z = mldivide(X,Y) +%MLDIVIDE Slash left division for tensors. +% +% MLDIVIDE(A,B) is called for the syntax 'A \ B' when A is a scalar and B +% is a tensor. +% +% Example +% X = tenrand([4 3 2],5); +% 3 \ X +% +% See also TENSOR, TENSOR/LDIVIDE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isscalar(X) + Z = tenfun(@ldivide,X,Y); + return; +end + +error('MLDIVIDE only supports the scalar case for tensors'); + diff --git a/external/tensor_toolbox_2.5/@tensor/mrdivide.m b/external/tensor_toolbox_2.5/@tensor/mrdivide.m new file mode 100755 index 0000000..03f0714 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/mrdivide.m @@ -0,0 +1,31 @@ +function Z = mrdivide(X,Y) +%MRDIVIDE Slash right division for tensors. +% +% MRDIVIDE(A,B) is called for the syntax 'A / B' when A is a tensor and B +% is a scalar. +% +% Example +% X = tenrand([4 3 2],5); +% X / 3 +% +% See also TENSOR, TENSOR/RDIVIDE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isscalar(Y) + Z = tenfun(@rdivide,X,Y); + return; +end + +error('MRDIVIDE only supports the scalar case for tensors'); + diff --git a/external/tensor_toolbox_2.5/@tensor/mtimes.m b/external/tensor_toolbox_2.5/@tensor/mtimes.m new file mode 100755 index 0000000..b991b73 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/mtimes.m @@ -0,0 +1,47 @@ +function C = mtimes(A,B) +%MTIMES tensor-scalar multiplication. +% +% C = MTIMES(A,B) is called for the syntax 'A * B' when A or B is a +% tensor and the other argument is a scalar. +% +% For tensor-matrix multiplication, use TTM. +% For tensor-tensor multiplication, use TTT. +% For tensor-tensor array multiplication, use TIMES or 'A .* B'. +% +% Examples +% X = tenrand([3,4,2]) +% W = 5 * X +% +% See also TENSOR, TENSOR/TTM, TENSOR/TTT, TENSOR/TIMES +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% +if isscalar(B) + C = A; + C.data = B * C.data; + return; +end + +if isscalar(A) + C = B; + C.data = A * C.data; + return; +end + +error('Mtimes only supports a tensor times a scalar'); + + + + + diff --git a/external/tensor_toolbox_2.5/@tensor/mttkrp.m b/external/tensor_toolbox_2.5/@tensor/mttkrp.m new file mode 100755 index 0000000..b2ed31a --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/mttkrp.m @@ -0,0 +1,49 @@ +function V = mttkrp(X,U,n) +%MTTKRP Matricized tensor times Khatri-Rao product for tensor. +% +% V = MTTKRP(X,U,n) efficiently calculates the matrix product of the +% n-mode matricization of X with the Khatri-Rao product of all +% entries in U, a cell array of matrices, except the nth. How to +% most efficiently do this computation depends on the type of tensor +% involved. +% +% See also TENSOR, TENMAT, KHATRIRAO +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +N = ndims(X); +if (N < 2) + error('MTTKRP is invalid for tensors with fewer than 2 dimensions'); +end + +if (length(U) ~= N) + error('Cell array is the wrong length'); +end + +if n == 1 + R = size(U{2},2); +else + R = size(U{1},2); +end + +for i = 1:N + if i == n, continue; end + if (size(U{i},1) ~= size(X,i)) || (size(U{i},2) ~= R) + error('Entry %d of cell array is wrong size', i); + end +end + +Xn = permute(X,[n 1:n-1,n+1:N]); +Xn = reshape(Xn.data, size(X,n), prod(size(X))/size(X,n)); %#ok +Z = khatrirao(U{[1:n-1,n+1:N]},'r'); +V = Xn*Z; diff --git a/external/tensor_toolbox_2.5/@tensor/ndims.m b/external/tensor_toolbox_2.5/@tensor/ndims.m new file mode 100755 index 0000000..6d8006c --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/ndims.m @@ -0,0 +1,25 @@ +function n = ndims(t) +%NDIMS Return the number of dimensions of a tensor. +% +% NDIMS(X) returns the number of dimensions of tensor X. +% +% Examples +% A = rand(4,3,1); ndims(A) %<-- Returns 2 +% X = tensor(A); ndims(X) %<-- Returns 2 +% X = tensor(A,[4 3 1]); ndims(X) %<-- Returns 3 +% +% See also TENSOR +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +n = numel(t.size); diff --git a/external/tensor_toolbox_2.5/@tensor/ne.m b/external/tensor_toolbox_2.5/@tensor/ne.m new file mode 100755 index 0000000..c31af52 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/ne.m @@ -0,0 +1,18 @@ +function Z = ne(X,Y) +%NE Not equal (~=) for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@ne,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/nnz.m b/external/tensor_toolbox_2.5/@tensor/nnz.m new file mode 100755 index 0000000..a9da866 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/nnz.m @@ -0,0 +1,18 @@ +function n = nnz(x) +%NNZ Number of nonzeros for tensors. +% +% See also TENSOR, SPTENSOR/NNZ. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +n = nnz(x.data); diff --git a/external/tensor_toolbox_2.5/@tensor/norm.m b/external/tensor_toolbox_2.5/@tensor/norm.m new file mode 100755 index 0000000..f827bb0 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/norm.m @@ -0,0 +1,21 @@ +function n = norm(T) +%NORM Frobenius norm of a tensor. +% +% NORM(X) returns the Frobenius norm of a tensor. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +v = reshape(T.data, numel(T.data), 1); +n = norm(v); diff --git a/external/tensor_toolbox_2.5/@tensor/not.m b/external/tensor_toolbox_2.5/@tensor/not.m new file mode 100755 index 0000000..98ab3cd --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/not.m @@ -0,0 +1,18 @@ +function B = not(A) +%NOT Logical NOT (~) for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +B = tensor(not(A.data), size(A)); diff --git a/external/tensor_toolbox_2.5/@tensor/nvecs.m b/external/tensor_toolbox_2.5/@tensor/nvecs.m new file mode 100755 index 0000000..a5ce134 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/nvecs.m @@ -0,0 +1,58 @@ +function u = nvecs(X,n,r,opts) +%NVECS Compute the leading mode-n vectors for a tensor. +% +% U = NVECS(X,n,r) computes the r leading eigenvalues of Xn*Xn' +% (where Xn is the mode-n matricization of X), which provides +% information about the mode-n fibers. In two-dimensions, the r +% leading mode-1 vectors are the same as the r left singular vectors +% and the r leading mode-2 vectors are the same as the r right +% singular vectors. +% +% U = NVECS(X,n,r,OPTS) specifies options: +% OPTS.eigsopts: options passed to the EIGS routine [struct('disp',0)] +% OPTS.flipsign: make each column's largest element positive [true] +% +% See also TENSOR, TENMAT, EIGS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ~exist('opts','var') + opts = struct; +end + +if isfield(opts,'eigsopts') + eigsopts = opts.eigsopts; +else + eigsopts.disp = 0; +end + +Xn = double(tenmat(X,n)); +Y = Xn*Xn'; + +[u,d] = eigs(Y, r, 'LM', eigsopts); + +if isfield(opts,'flipsign') + flipsign = opts.flipsign; +else + flipsign = true; +end + +if flipsign + % Make the largest magnitude element be positive + [val,loc] = max(abs(u)); + for i = 1:r + if u(loc(i),i) < 0 + u(:,i) = u(:,i) * -1; + end + end +end diff --git a/external/tensor_toolbox_2.5/@tensor/or.m b/external/tensor_toolbox_2.5/@tensor/or.m new file mode 100755 index 0000000..fcdb19e --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/or.m @@ -0,0 +1,18 @@ +function Z = or(X,Y) +%OR Logical OR (|) for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@or,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/permute.m b/external/tensor_toolbox_2.5/@tensor/permute.m new file mode 100755 index 0000000..f997903 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/permute.m @@ -0,0 +1,46 @@ +function T = permute(T,order) +%PERMUTE Permute tensor dimensions. +% +% B = PERMUTE(A,ORDER) rearranges the dimensions of A so that they +% are in the order specified by the vector ORDER. The result has the +% same values of A, but the order of the subscripts needed to access +% any particular element are rearranged as specified by ORDER. +% +% See also TENSOR, TENSOR/SIZE, TENSOR/NDIMS, PERMUTE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ndims(T) ~= numel(order) + error('Invalid permutation order'); +end + +% Check for special case of permuting an order-1 object (which has +% no effect but confuses MATLAB's permute command which doesn't +% think that there is such a thing as a 1D-array). +if isequal(order,1) + return; +end + +% Check for special case of empty object (which has +% no effect but confuses MATLAB's permute command which doesn't +% think that there is such a thing as an empty array). +if isempty(order) + return; +end + +% Note that permute does error checking on order, so we don't worry +% about it. +T.data = permute(T.data,order); +T.size = T.size(order); + +return; diff --git a/external/tensor_toolbox_2.5/@tensor/plus.m b/external/tensor_toolbox_2.5/@tensor/plus.m new file mode 100755 index 0000000..f9a826f --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/plus.m @@ -0,0 +1,22 @@ +function Z = plus(X,Y) +%PLUS Binary addition (+) for tensors. +% +% PLUS(A,B) is called for the syntax 'A + B' when A or B is a tensor. A +% and B must have the same size, unless one is a scalar. A scalar can be +% added to a tensor of any size. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@plus,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/power.m b/external/tensor_toolbox_2.5/@tensor/power.m new file mode 100755 index 0000000..e00577e --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/power.m @@ -0,0 +1,18 @@ +function Z = power(X,Y) +%POWER Elementwise power (.^) operator for a tensor. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@power,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/rdivide.m b/external/tensor_toolbox_2.5/@tensor/rdivide.m new file mode 100755 index 0000000..2adce31 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/rdivide.m @@ -0,0 +1,26 @@ +function Z = rdivide(X,Y) +%RDIVIDE Right array divide for tensors. +% +% RDIVIDE(A,B) is called for the syntax 'A ./ B' when A or B is a tensor. +% A and B must have the same size, unless one is a scalar. +% +% Examples +% X = tenrand([4 3 2],5); +% X ./ 3 +% X ./ X +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@rdivide,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/reshape.m b/external/tensor_toolbox_2.5/@tensor/reshape.m new file mode 100755 index 0000000..0857e7a --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/reshape.m @@ -0,0 +1,25 @@ +function t = reshape(t,siz) +%RESHAPE Change tensor size. +% RESHAPE(X,SIZ) returns the tensor whose elements +% have been reshaped to the appropriate size. +% +% See also SQUEEZE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if prod(t.size) ~= prod(siz) + error('Number of elements cannot change'); +end + +t.data = reshape(t.data,siz); +t.size = siz; diff --git a/external/tensor_toolbox_2.5/@tensor/scale.m b/external/tensor_toolbox_2.5/@tensor/scale.m new file mode 100755 index 0000000..5663f7e --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/scale.m @@ -0,0 +1,71 @@ +function Y = scale(X,S,dims) +%SCALE Scale along specified dimensions of tensor. +% +% Y = SCALE(X,S,DIMS) scales the tensor X along the dimension(s) +% specified in DIMS using the scaling data in S. If DIMS contains +% only one dimension, then S can be a column vector. Otherwise, S +% should be a tensor. +% +% Examples +% X = tenones([3,4,5]); +% S = 10 * [1:5]'; Y = scale(X,S,3) +% S = tensor(10 * [1:5]',5); Y = scale(X,S,3) +% S = tensor(1:12,[3 4]); Y = scale(X,S,[1 2]) +% S = tensor(1:12,[3 4]); Y = scale(X,S,-3) +% S = tensor(1:60,[3 4 5]); Y = scale(X,S,1:3) +% +% See also TENSOR, TENSOR/COLLAPSE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +dims = tt_dimscheck(dims,ndims(X)); +remdims = setdiff(1:ndims(X),dims); + +% Convert to a matrix so that each column of A can be scaled by a +% vectorized version of S. +A = double(tenmat(X,dims,remdims)); + +switch(class(S)) + case {'tensor'} + if ~isequal(size(S), X.size(dims)) + error 'Size mismatch'; + end + % Vectorize S. + S = double(tenmat(S,1:ndims(S),[])); + case {'double'} + if size(S,1) ~= X.size(dims) + error 'Size mismatch'; + end + otherwise + error('Invalid scaling factor'); +end + +[m,n] = size(A); + +% If the size of S is pretty small, we can convert it to a diagonal matrix +% and multiply by A. Otherwise, we scale A column-by-column. +if (m <= n) + B = diag(S) * A; +else + B = zeros(size(A)); + for j = 1:n + B(:,j) = S .* A(:,j); + end +end + +% Convert the matrix B back into a tensor and return. +Y = tensor(tenmat(B,dims,remdims,X.size)); + + + + diff --git a/external/tensor_toolbox_2.5/@tensor/size.m b/external/tensor_toolbox_2.5/@tensor/size.m new file mode 100755 index 0000000..b3d8cb8 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/size.m @@ -0,0 +1,38 @@ +function m = size(t,idx) +%SIZE Tensor dimensions. +% +% D = SIZE(T) returns the sizes of each dimension of tensor X in a +% vector D with ndims(X) elements. +% +% I = size(T,DIM) returns the size of the dimension specified by +% the scalar DIM. +% +% Examples +% A = rand(3,4,2,1); T = tensor(A,[3 4 2 1]); +% size(A) %<-- returns a length-3 vector +% size(T) %<-- returns a length-4 vector +% size(A,2) %<-- returns 4 +% size(T,2) %<-- same +% size(A,5) %<-- returns 1 +% size(T,5) %<-- ERROR! +% +% See also TENSOR, TENSOR/NDIMS, SIZE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +if exist('idx','var') + m = t.size(idx); +else + m = t.size; +end diff --git a/external/tensor_toolbox_2.5/@tensor/squeeze.m b/external/tensor_toolbox_2.5/@tensor/squeeze.m new file mode 100755 index 0000000..5247ef6 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/squeeze.m @@ -0,0 +1,42 @@ +function Y = squeeze(X) +%SQUEEZE Remove singleton dimensions from a tensor. +% +% Y = SQUEEZE(X) returns a tensor Y with the same elements as +% X but with all the singleton dimensions removed. A singleton +% is a dimension such that size(X,dim)==1. +% +% If X has *only* singleton dimensions, then Y is a scalar. +% +% Examples +% squeeze( tenrand([2,1,3]) ) %<-- returns a 2-by-3 tensor +% squeeze( tenrand([1 1]) ) %<-- returns a scalar +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if all(X.size > 1) + % No singleton dimensions to squeeze + Y = X; +else + idx = find(X.size > 1); + if numel(idx) == 0 + % Scalar case - only singleton dimensions + Y = X.data; + else + siz = X.size(idx); + Y = tensor(squeeze(X.data),siz); + end +end + +return; diff --git a/external/tensor_toolbox_2.5/@tensor/subsasgn.m b/external/tensor_toolbox_2.5/@tensor/subsasgn.m new file mode 100755 index 0000000..418917e --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/subsasgn.m @@ -0,0 +1,139 @@ +function x = subsasgn(x,s,b) +%SUBSASGN Subscripted assignment for a tensor. +% +% We can assign elements to a tensor in three ways. +% +% Case 1: X(R1,R2,...,RN) = Y, in which case we replace the +% rectangular subtensor (or single element) specified by the ranges +% R1,...,RN with Y. The right-hand-side can be a scalar, a tensor, or an +% MDA. +% +% Case 2a: X(S) = V, where S is a p x n array of subscripts and V is +% a scalar or a vector containing p values. +% +% Case 2b: X(I) = V, where I is a set of p linear indices and V is a +% scalar or a vector containing p values. Resize is not allowed in this +% case. +% +% Examples +% X = tensor(rand(3,4,2)) +% X(1:2,1:2,1) = ones(2,2) %<-- replaces subtensor +% X([1 1 1;1 1 2]) = [5;7] %<-- replaces two elements +% X([1;13]) = [5;7] %<-- does the same thing +% X(1,1,2:3) = 1 %<-- grows tensor +% X(1,1,4) = 1 %<- grows the size of the tensor +% +% See also TENSOR, TENSOR/SUBSREF. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +switch s.type + case '.' + error(['Cannot change field ', s.subs, ' directly.']); + + case '{}' + error('Subscript cell reference not supported for tensor.'); + + case '()' + + % We don't allow sub-subscriptingfor tensors. + if numel(s) ~= 1 + error('Invalid subscripting'); + end + + % Figure out if we are doing a subtensor, a list of subscripts, or + % a list of linear indices... + type = 'error'; + if ndims(x) <= 1 + if (numel(s.subs) > 1) || ... + ((ndims(s.subs{1}) == 2) && ... + (size(s.subs{1},1) == 1 || size(s.subs{1},2) == 1)) + type = 'subtensor'; + elseif ndims(s.subs{1}) == 2 + type = 'subscripts'; + end + else + if numel(s.subs) >= ndims(x) + type = 'subtensor'; + elseif ndims(s.subs{1}) == 2 + if size(s.subs{1},2) >= ndims(x) + type = 'subscripts'; + elseif size(s.subs{1},2) == 1 + type = 'linear indicies'; + end + end + end + + + % *** CASE 1: Rectangular Subtensor *** + if isequal(type,'subtensor') + if isa(b,'tensor') + x.data(s.subs{:},1) = b.data; + else + x.data(s.subs{:},1) = b; + end + % Check if the size has grown! + % Can't vectorize this due to possible trailing 1's + for i = 1:numel(x.size) + x.size(i) = max(x.size(i),size(x.data,i)); + end + % Check if order has grown + for i = numel(x.size)+1:numel(s.subs) + x.size(i) = size(x.data,i); + end + return; + end + + % *** CASE 2a: Subscript indexing *** + if isequal(type,'subscripts'); + + % extract array of subscripts + subs = s.subs{1}; + + % will the size change? if so, we first need to resize x + n = ndims(x); + bsiz = max(subs,[],1); + newsiz = [max([x.size;bsiz(1:n)]) bsiz(n+1:end)]; + if ~isequal(newsiz,x.size) + % We need to enlarge x.data. A trick is to assign its last + % "new" element to zero. This resizes the array correctly. + if numel(newsiz) == 1 + str = sprintf('x.data(%d)=0;',newsiz); + else + str = [sprintf('x.data(') ... + sprintf('%d,',newsiz(1:end-1)) ... + sprintf('%d)=0;', newsiz(end)) ]; + end + eval(str); + x.size = newsiz; + end + + % finally, we can copy in the new data + x.data(tt_sub2ind(newsiz,subs)) = b; + return; + end + + % *** CASE 2b: Linear indexing *** + if isequal(type,'linear indicies'); + idx = s.subs{1}; + x.data (idx) = b; + return + end + + error('Invalid use of tensor/subsasgn'); +end + + + + + diff --git a/external/tensor_toolbox_2.5/@tensor/subsref.m b/external/tensor_toolbox_2.5/@tensor/subsref.m new file mode 100755 index 0000000..fd3f20e --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/subsref.m @@ -0,0 +1,131 @@ +function a = subsref(t,s) +%SUBSREF Subscripted reference for tensors. +% +% We can extract elements or subtensors from a tensor in the +% following ways. +% +% Case 1a: y = X(i1,i2,...,iN), where each in is an index, returns a +% scalar. +% +% Case 1b: Y = X(R1,R2,...,RN), where one or more Rn is a range and +% the rest are indices, returns a sparse tensor. +% +% Case 2a: V = X(S) or V = X(S,'extract'), where S is a p x n array +% of subscripts, returns a vector of p values. +% +% Case 2b: V = X(I) or V = X(I,'extract'), where I is a set of p +% linear indices, returns a vector of p values. +% +% Any ambiguity results in executing the first valid case. This +% is particularly an issue if ndims(X)==1. +% +% Examples +% X = tensor(rand(3,4,2,1),[3 4 2 1]); +% X(1,1,1,1) %<-- produces a scalar +% X(1,1,1,:) %<-- produces a tensor of order 1 and size 1 +% X(:,1,1,:) %<-- produces a tensor of size 3 x 1 +% X(1:2,[2 4],1,:) %<-- produces a tensor of size 2 x 2 x 1 +% X(1:2,[2 4],1,1) %<-- produces a tensor of size 2 x 2 +% X([1,1,1,1;3,4,2,1]) %<-- returns a vector of length 2 +% X = tensor(rand(10,1),10); +% X([1:6]') %<-- extracts a subtensor +% X([1:6]','extract') %<-- extracts a vector of 6 elements +% +% See also TENSOR, TENSOR/FIND. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +switch s(1).type + case '{}' + error('Cell contents reference from a non-cell array object.') + case '.' + fieldname = s(1).subs; + switch fieldname + case 'data' + a = tt_subsubsref(t.data,s); + case 'size' + a = tt_subsubsref(t.size,s); + otherwise + error(['No such field: ', fieldname]); + end + case '()' + + % *** CASE 1: Rectangular Subtensor *** + if (numel(s(1).subs) == ndims(t)) && ~isequal(s(1).subs{end},'extract') + + % Copy the subscripts + region = s(1).subs; + + if numel(region) ~= ndims(t) + error('Invalid number of subscripts'); + end + + % Extract the data + newdata = t.data(region{:}); + + % Determine the subscripts + newsiz = []; % (future) new size + kpdims = []; % dimensions to keep + rmdims = []; % dimensions to remove + + % Determine the new size and what dimensions to keep + for i = 1:length(region) + if ischar(region{i}) && (region{i} == ':') + newsiz = [newsiz size(t,i)]; + kpdims = [kpdims i]; + elseif numel(region{i}) > 1 + newsiz = [newsiz numel(region{i})]; + kpdims = [kpdims i]; + else + rmdims = [rmdims i]; + end + end + + % If the size is zero, then the result is returned as a scalar; + % otherwise, we convert the result to a tensor. + if isempty(newsiz) + a = newdata; + else + if isempty(rmdims) + a = tensor(newdata,newsiz); + else + a = tensor(permute(newdata,[kpdims rmdims]),newsiz); + end + end + a = tt_subsubsref(a,s); + return; + end + + % *** CASE 2a: Subscript indexing + if size(s(1).subs{1},2) == ndims(t) + % extract array of subscripts + subs = s(1).subs{1}; + a = t.data(tt_sub2ind(t.size,subs)); + a = tt_subsubsref(a,s); + return; + end + + % *** CASE 2b: Linear indexing *** + if numel(s(1).subs) ~= 1 + error('Invalid indexing'); + end + + idx = s(1).subs{1}; + if ndims(idx) ~=2 || size(idx,2) ~= 1 + error('Expecting a column index'); + end + + a = t.data(idx); + a = tt_subsubsref(a,s); + return; +end diff --git a/external/tensor_toolbox_2.5/@tensor/symmetrize.m b/external/tensor_toolbox_2.5/@tensor/symmetrize.m new file mode 100755 index 0000000..aa64027 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/symmetrize.m @@ -0,0 +1,111 @@ +function Y = symmetrize(X,grps) +%SYMMETRIZE Symmetrize a tensor X in specified modes. +% +% Y = symmetrize(X) will symmetrize a tensor X with respect to all +% modes so that Y is symmetric with respect to any permutation of +% indices. +% +% Y = symmetrize(X,MODES) will symmetrix a tensor X with respect to the +% modes specified by the vector MODES of mode indices. The second +% argument may alternatively be a cell array of vectors of modes to, +% e.g., specify that it should be symmetric with respect to mode [1 3] as +% well as [2 4]. +% +% See also ISSYMMETRIC. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +%T. Kolda, April 2011 +n = ndims(X); +sz = size(X); + +% Check that grps exists; if not, create it. +if ~exist('grps','var') + grps = {1:n}; +end + +% Check that grps is a cell array. +if ~iscell(grps) + grps = {grps}; +end + +if ~isnumeric(grps{1}) + error('MODES must be numeric'); +end + +% Check tensor dimensions for compatibility with symmetrization +ngrps = length(grps); +for i = 1:ngrps + dims = grps{i}; + for j = dims(2:end) + if sz(j) ~= sz(dims(1)) + error('Dimension mismatch for symmetrization'); + end + end +end + +% Check for no overlap in the sets +for i = 1:ngrps + for j = i+1:ngrps + if ~isempty(intersect(grps{i},grps{j})) + error('Cannot haver overlapping symmetries'); + end + end +end + +% Create the combinations for each symmetrized subset +combos = cell(ngrps,1); +for i = 1:ngrps + combos{i} = perms(grps{i}); +end + +% Create all the permuations to be averaged +total_perms = prod(cellfun(@length,combos)); +sym_perms = repmat(1:n, total_perms, 1); +for i = 1:ngrps + ntimes = prod(cellfun(@length,combos(1:i-1))); + ncopies = prod(cellfun(@length,combos(i+1:end))); + nelems = length(combos{i}); + + idx = 1; + for j = 1:ntimes + for k = 1:nelems + for l = 1:ncopies + sym_perms(idx,grps{i}) = combos{i}(k,:); + idx = idx + 1; + end + end + end +end + +% Create an average tensor +Y = tenzeros(size(X)); +for i = 1:total_perms + Y = Y + permute(X,sym_perms(i,:)); +end +Y = Y / total_perms; + +% It's not *exactly* symmetric due to oddities in differently ordered +% summations and so on, so let's fix that. +% Idea borrowed from Gergana Bounova: +% http://www.mit.edu/~gerganaa/downloads/matlab/symmetrize.m +for i = 1:total_perms + Z = permute(Y,sym_perms(i,:)); + Y.data(:) = max(Y.data(:),Z.data(:)); +end + + + + + + + diff --git a/external/tensor_toolbox_2.5/@tensor/tenfun.m b/external/tensor_toolbox_2.5/@tensor/tenfun.m new file mode 100755 index 0000000..811c8da --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/tenfun.m @@ -0,0 +1,132 @@ +function Z = tenfun(fun,varargin) +%TENFUN Apply a function to each element in a tensor. +% +% TENFUN(F,X,...) applies the function specified by the function +% handle F to the given arguments. Either both arguments +% must be tensors, or one is a tensor and the other is a scalar/MDA. +% +% Examples +% Z = tenfun(@(x)(x+1),X) %<-- increase every element by one +% Z = tenfun(@eq,X,1) %<-- logical comparison of X with scalar +% Z = tenfun(@plus,X,Y) %<-- adds the two tensors X and Y. +% Z = tenfun(@max,X,Y,Z) %<-- max over all elements in X,Y,Z +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if nargin < 2 + % error('TENFUN requires at least two input arguments') + error('Not enough input arguments.'); +end + +if ~isa(fun, 'function_handle') + error('First argument must be a function handle.'); +end + +%% Case I: NARGIN == 2 (one function and one tensor) +if (nargin == 2) && isa(varargin{1},'tensor') + Z = varargin{1}; + Z.data(:) = fun(Z.data(:)); + return; +end + +%% Determine if function is binary +% Note that we swap the arguments below if 2nd argument is sparse, but need +% to take special measures for those functions that don't commute. +binfuns = {@plus,@minus,@eq,@ge,@gt,@le,@lt,@ne,@and,@or,@xor, ... + @power,@times,@ldivide,@rdivide}; +isbinary = false; +for i = 1 : numel(binfuns) + if isequal(fun,binfuns{i}) + isbinary = true; + break; + end +end + +%% Case II: NARGIN == 3 and function is binary +if (nargin == 3) && isbinary + + X = varargin{1}; + Y = varargin{2}; + + % Case IIa: X is a scalar/MDA and Y is a tensor + if isnumeric(X) && isa(Y,'tensor') + Z = Y; + Z.data = fun(X,Y.data); + return; + end + + % Case IIb: X is a tensor and Y is a scalar/MDA + if isa(X,'tensor') && isnumeric(Y) + Z = X; + Z.data = fun(X.data,Y); + return; + end + + % Case IIc: X and Y are both tensors + if isa(X,'tensor') && isa(Y,'tensor') + if ~(isequal(size(X),size(Y))) + error('Tensor size mismatch.') + end + data = fun(X.data,Y.data); + Z = tensor(data,size(X)); + return; + end + + % Case IId: Either X or Y is a sptensor + if isa(X,'tensor') && isa(Y,'sptensor') + if isequal(fun,@lt) + Z = gt(Y,X); + elseif isequal(fun,@le) + Z = ge(Y,X); + elseif isequal(fun,@gt) + Z = lt(Y,X); + elseif isequal(fun,@ge) + Z = le(Y,X); + elseif isequal(fun,@minus) + Z = plus(-Y,X); + elseif isequal(fun,@power) + error('Cannot do array power with a sparse and dense tensor'); + elseif isequal(fun,@ldivide) + error('Cannot do ldivide with a sparse and dense tensor'); + elseif isequal(fun,@rdivide) + error('Cannot do rdivide with a sparse and dense tensor'); + else + Z = fun(Y,X); + end + return; + end + + % Case IIe: Either X or Y is not a tensor + error('For a binary function, arguments must be either two tensors or one tensor and a scalar/MDA.'); +end + +%% Case III: one function and the rest are same-sized tensors + +X = varargin; +n = numel(X); +sz = size(X{1}); +m = prod(sz); +Y = zeros(m,n); +for j = 1:n + Y(:,j) = X{j}.data(:); +end +data = zeros(m,1); +for i = 1:m + data(i) = fun(Y(i,:)); +end +Z = tensor(data,sz); +return; + + diff --git a/external/tensor_toolbox_2.5/@tensor/tensor.m b/external/tensor_toolbox_2.5/@tensor/tensor.m new file mode 100755 index 0000000..d754694 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/tensor.m @@ -0,0 +1,123 @@ +function t = tensor(varargin) +%TENSOR Create tensor. +% +% X = TENSOR(A,SIZ) creates a tensor from the multidimensional +% array A. The SIZ argument specifies the desired shape of A. +% +% X = TENSOR(A) creates a tensor from the multidimensional array +% Z, using SIZ = size(A). +% +% X = TENSOR(S) copies a tensor S. +% +% X = TENSOR(A) converts an sptensor, ktensor, ttensor, or tenmat object +% to a tensor. +% +% X = TENSOR creates an empty, dense tensor object. +% +% Examples +% X = tensor(rand(3,4,2)) %<-- Tensor of size 3 x 4 x 2 +% Y = tensor(rand(3,1),3) %<-- Tensor of size 3 +% Z = tensor(rand(12,1),[3 4 1]) %<-- Tensor of size 3 x 4 x 1 +% +% See also TENMAT, SPTENSOR, KTENSOR, TTENSOR, TENSOR/NDIMS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% EMPTY/DEFAULT CONSTRUCTOR +if nargin == 0 + t.data = []; + t.size = []; + t = class(t, 'tensor'); + return; +end + +% CONVERSION/COPY CONSTRUCTORS +% Note that we pass through this if/switch statement if the first argument +% is not any of these cases. +if (nargin == 1) + v = varargin{1}; + switch class(v) + case 'tensor', + % COPY CONSTRUCTOR + t.data = v.data; + t.size = v.size; + t = class(t, 'tensor'); + return; + case {'ktensor','ttensor','sptensor'}, + % CONVERSION + t = full(v); + return; + case 'tenmat', + % RESHAPE TENSOR-AS-MATRIX + % Here we just reverse what was done in the tenmat constructor. + % First we reshape the data to be an MDA, then we un-permute + % it using ipermute. + sz = tsize(v); + order = [v.rdims,v.cdims]; + data = reshape(v.data, [sz(order) 1 1]); + if numel(order) >= 2 + t.data = ipermute(data,order); + else + t.data = data; + end + t.size = sz; + t = class(t, 'tensor'); + return; + end +end + +% CONVERT A MULTIDIMENSIONAL ARRAY +if (nargin <= 2) + + % Check first argument + data = varargin{1}; + if ~isa(data,'numeric') && ~isa(data,'logical') + error('First argument must be a multidimensional array.') + end + + % Create or check second argument + if nargin == 1 + siz = size(data); + else + siz = varargin{2}; + if ~isempty(siz) && ndims(siz) ~= 2 && size(siz,1) ~= 1 + error('Second argument must be a row vector.'); + end + end + + % Make sure the number of elements matches what's been specified + if isempty(siz) + if ~isempty(data) + error('Empty tensor cannot contain any elements'); + end + elseif prod(siz) ~= numel(data) + error('Size of data does not match specified size of tensor'); + end + + % Make sure the data is indeed the right shape + if ~isempty(data) && ~isempty(siz) + data = reshape(data,[siz 1 1]); + end + + % Create the tensor + t.data = data; + t.size = siz; + t = class(t, 'tensor'); + return; + +end + + +error('Unsupported use of function TENSOR.'); + + diff --git a/external/tensor_toolbox_2.5/@tensor/times.m b/external/tensor_toolbox_2.5/@tensor/times.m new file mode 100755 index 0000000..209c76b --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/times.m @@ -0,0 +1,26 @@ +function Z = times(X,Y) +%TIMES Array multiplication for tensors. +% +% TIMES(A,B) is called for the syntax 'A .* B' when A or B is a +% tensor. A and B must have the same size, unless one is a scalar. A +% scalar can be multiplied by a tensor of any size. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isa(Y,'ktensor') || isa(Y,'ttensor') || isa(Y,'sptensor') + Y = full(Y); +end + +Z = tenfun(@times,X,Y); diff --git a/external/tensor_toolbox_2.5/@tensor/transpose.m b/external/tensor_toolbox_2.5/@tensor/transpose.m new file mode 100755 index 0000000..b52f27b --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/transpose.m @@ -0,0 +1,18 @@ +function transpose(x) +%TRANSPOSE is not defined on tensors. +% +% See also TENSOR/PERMUTE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +error('Transpose on tensor is not defined'); diff --git a/external/tensor_toolbox_2.5/@tensor/ttm.m b/external/tensor_toolbox_2.5/@tensor/ttm.m new file mode 100755 index 0000000..062e88a --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/ttm.m @@ -0,0 +1,118 @@ +function Y = ttm(X,V,varargin) +%TTM Tensor times matrix. +% +% Y = TTM(X,A,N) computes the n-mode product of tensor X with a +% matrix A; i.e., X x_N A. The integer N specifies the dimension +% (or mode) of X along which A should be multiplied. If size(A) = +% [J,I], then X must have size(X,N) = I. The result will be the +% same order and size as X except that size(Y,N) = J. +% +% Y = TTM(X,{A,B,C,...}) computes the n-mode product of tensor X +% with a sequence of matrices in the cell array. The n-mode +% products are computed sequentially along all dimensions (or modes) +% of X. The cell array contains ndims(X) matrices. +% +% Y = TTM(X,{A,B,C,...},DIMS) computes the sequence tensor-matrix +% products along the dimensions specified by DIMS. +% +% Y = TTM(...,'t') performs the same computations as above except +% the matrices are transposed. +% +% Examples +% X = tensor(rand(5,3,4,2)); +% A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2); +% Y = ttm(X, A, 1) %<-- computes X times A in mode-1 +% Y = ttm(X, {A,B,C,D}, 1) %<-- same as above +% Y = ttm(X, A', 1, 't') %<-- same as above +% Y = ttm(X, {A,B,C,D}, [1 2 3 4]) %<-- 4-way multiply +% Y = ttm(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above +% Y = ttm(X, {A,B,C,D}) %<-- same as above +% Y = ttm(X, {A',B',C',D'}, 't') %<-- same as above +% Y = ttm(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4 +% Y = ttm(X, {A,B,C,D}, [3 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, [1 2 4]) %<-- 3-way multiply +% Y = ttm(X, {A,B,C,D}, [1 2 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, -3) %<-- same as above +% Y = ttm(X, {A,B,C,D}, -3) %<-- same as above +% +% See also TENSOR, TENSOR/TTT, TENSOR/TTV. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +%% Check the number of arguments +if (nargin < 2) + error('TTM requires at least two arguments.'); +end + +%% Create 'n' and 'tflag' arguments from varargin +n = 1:ndims(X); +tflag = ''; +if numel(varargin) == 1 + if ischar(varargin{1}) + tflag = varargin{1}; + else + n = varargin{1}; + end +elseif numel(varargin) == 2 + n = varargin{1}; + tflag = varargin{2}; +end + +%% Handle cell array +if iscell(V) + % Copy n into dims + dims = n; + % Check that the dimensions are valid + [dims,vidx] = tt_dimscheck(dims,ndims(X),numel(V)); + % Calculate individual products + Y = ttm(X, V{vidx(1)}, dims(1), tflag); + for i = 2 : numel(dims) + Y = ttm(Y, V{vidx(i)}, dims(i), tflag); + end + % All done + return; +end + +%% Check the second argument +if ndims(V) ~= 2 + error('tensor/ttm: 2nd argument must be a matrix.'); +end + +%% Check n +if (numel(n) ~= 1 || (n < 0) || n > ndims(X)) + error('Dimension N must be between 1 and NDIMS(X).'); +end + +%% COMPUTE THE PRODUCT + +N = ndims(X); +sz = size(X); +order = [n,1:n-1,n+1:N]; +newdata = double(permute(X,order)); +newdata = reshape(newdata,sz(n),prod(sz([1:n-1,n+1:N]))); +if tflag == 't' + newdata = V'*newdata; + p = size(V,2); +else + newdata = V*newdata; + p = size(V,1); +end +newsz = [p,sz(1:n-1),sz(n+1:N)]; +Y = tensor(newdata,newsz); +Y = ipermute(Y,order); + + +return; + +end diff --git a/external/tensor_toolbox_2.5/@tensor/ttsv.m b/external/tensor_toolbox_2.5/@tensor/ttsv.m new file mode 100755 index 0000000..f9b0171 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/ttsv.m @@ -0,0 +1,48 @@ +function y = ttsv(A,x,n) +%TTSV Tensor times same vector in multiple modes. +% +% Y = TTSV(A,X) multiples the tensor A by the vector X in all modes. +% +% Y = TTSV(A,X,-1) multiplies the tensor A by the vector X in all modes +% but the first. Returns the answer as a normal MATLAB array (not a +% tensor). +% +% Y = TTSV(A,X,-2) multiplies the tensor A by the vector X in all modes +% but the first two. Returns the answer as a normal MATLAB matrix (not a +% tensor). +% +% Y = TTSV(A,X,-N) multiplies the tensor A by the vector X is all modes +% but the first N. +% +% See also TENSOR/TTV. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +%% Process inputs (only two simple cases are supported) +if ~exist('n','var') + n = 0; +elseif (n > 0) + error('Invalid usage'); +end + +%% Create X. +P = ndims(A); +[X{1:P}] = deal(x); + +%% Calculate +if (n == 0) + y = ttv(A,X); +elseif (n == -1) || (n == -2) + y = double(ttv(A,X,-(1:-n))); +else + y = ttv(A,X,-(1:-n)); +end diff --git a/external/tensor_toolbox_2.5/@tensor/ttt.m b/external/tensor_toolbox_2.5/@tensor/ttt.m new file mode 100755 index 0000000..82ff28a --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/ttt.m @@ -0,0 +1,94 @@ +function c = ttt(varargin) +%TTT Tensor mulitplication (tensor times tensor). +% +% TTT(X,Y) computes the outer product of tensors X and Y. +% +% TTT(X,Y,XDIMS,YDIMS) computes the contracted product of tensors +% X and Y in the dimensions specified by the row vectors XDIMS and +% YDIMS. The sizes of the dimensions specified by XDIMS and YDIMS +% must match; that is, size(X,XDIMS) must equal size(Y,YDIMS). +% +% TTT(X,Y,DIMS) computes the inner product of tensors X and Y in the +% dimensions specified by the vector DIMS. The sizes of the +% dimensions specified by DIMS must match; that is, size(X,DIMS) must +% equal size(Y,DIMS). +% +% Examples +% X = tensor(rand(4,2,3)); +% Y = tensor(rand(3,4,2)); +% Z = ttt(X,Y) %<-- outer product of X and Y +% Z = ttt(X,X,1:3) %<-- inner product of X with itself +% Z = ttt(X,Y,[1 2 3],[2 3 1]) %<-- inner product of X & Y +% Z = ttt(X,Y,[1 3],[2 1]) %<-- product of X & Y along specified dims +% +% See also TENSOR, TENSOR/TTM, TENSOR/TTV. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +%%%%%%%%%%%%%%%%%%%%%% +%%% ERROR CHECKING %%% +%%%%%%%%%%%%%%%%%%%%%% + +% Check the number of arguments +if (nargin < 2) + error('TTT requires at least two arguments.'); +end + +% Check the first argument +if ~isa(varargin{1}, 'tensor') + error('First argument must be a tensor.'); +else + a = varargin{1}; +end + +% Check the second argument +if ~isa(varargin{2}, 'tensor') + error('Second argument must be a tensor.'); +else + b = varargin{2}; +end + +% Optional 3rd argument +if nargin >= 3 + adims = varargin{3}; +else + adims = []; +end + +% Optional 4th argument +if nargin >= 4 + bdims = varargin{4}; +else + bdims = adims; +end + +if ~isequal(size(a,adims),size(b,bdims)) + error('Specified dimensions do not match.'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% COMPUTE THE PRODUCT %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Avoid transpose by reshaping A and computing C = A * B +amatrix = tenmat(a,adims,'t'); +bmatrix = tenmat(b,bdims); +cmatrix = amatrix * bmatrix; + +% Check whether or not the result is a scalar. +if isa(cmatrix,'tenmat') + c = tensor(cmatrix); +else + c = cmatrix; +end diff --git a/external/tensor_toolbox_2.5/@tensor/ttv.m b/external/tensor_toolbox_2.5/@tensor/ttv.m new file mode 100755 index 0000000..06ba0ff --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/ttv.m @@ -0,0 +1,105 @@ +function c = ttv(a,v,dims) +%TTV Tensor times vector. +% +% Y = TTV(X,A,N) computes the product of tensor X with a (column) +% vector A. The integer N specifies the dimension in X along which +% A is multiplied. If size(A) = [I,1], then X must have size(X,N) = +% I. Note that ndims(Y) = ndims(X) - 1 because the N-th dimension +% is removed. +% +% Y = TTV(X,{A,B,C,...}) computes the product of tensor X with a +% sequence of vectors in the cell array. The products are computed +% sequentially along all dimensions (or modes) of X. The cell array +% contains ndims(X) vectors. +% +% Y = TTV(X,{A,B,C,...},DIMS) computes the sequence of tensor-vector +% products along the dimensions specified by DIMS. +% +% Examples +% X = tensor(rand(5,3,4,2)); +% A = rand(5,1); B = rand(3,1); C = rand(4,1); D = rand(2,1); +% Y = ttv(X, A, 1) %<-- X times A in mode 1 +% Y = ttv(X, {A,B,C,D}, 1) %<-- same as above +% Y = ttv(X, {A,B,C,D}, [1 2 3 4]) %<-- All-mode multiply +% Y = ttv(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above +% Y = ttv(X, {A,B,C,D}) %<-- same as above +% Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4 +% Y = ttv(X, {A,B,C,D}, [3 4]) %<-- same as above +% Y = ttv(X, {A,B,D}, [1 2 4]) %<-- 3-way mutplication +% Y = ttv(X, {A,B,C,D}, [1 2 4]) %<-- same as above +% Y = ttv(X, {A,B,D}, -3) %<-- same as above +% Y = ttv(X, {A,B,C,D}, -3) %<-- same as above +% +% See also TENSOR, TENSOR/TTT, TENSOR/TTM. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Check the number of arguments +if (nargin < 2) + error('TTV requires at least two arguments.'); +end + +% Check for 3rd argument +if ~exist('dims','var') + dims = []; +end + +% Check that 2nd argument is cell array. If not, recall with v as a +% cell array with one element. +if ~iscell(v) + c = ttv(a,{v},dims); + return; +end + +% Get sorted dims and index for multiplicands +[dims,vidx] = tt_dimscheck(dims,ndims(a),numel(v)); + +% Check that each multiplicand is the right size. +for i = 1:numel(dims) + if ~isequal(size(v{vidx(i)}),[size(a,dims(i)) 1]) + error('Multiplicand is wrong size'); + end +end + +if exist('tensor/ttv_single','file') == 3 + c = a; + for i = numel(dims) : -1 : 1 + c = ttv_single(c,v{vidx(i)},dims(i)); + end + return; +end + +% Extract the MDA +c = a.data; + +% Permute it so that the dimensions we're working with come last +remdims = setdiff(1:ndims(a),dims); +if (ndims(a) > 1) + c = permute(c,[remdims dims]); +end + +% Do each multiply in sequence, doing the highest index first, +% which is important for vector multiplies. +n = ndims(a); +sz = a.size([remdims dims]); +for i = numel(dims) : -1 : 1 + c = reshape(c,prod(sz(1:n-1)),sz(n)); + c = c * v{vidx(i)}; + n = n-1; +end + +% If needed, convert the final result back to a tensor +if (n > 0) + c = tensor(c,sz(1:n)); +end + diff --git a/external/tensor_toolbox_2.5/@tensor/uminus.m b/external/tensor_toolbox_2.5/@tensor/uminus.m new file mode 100755 index 0000000..db9fd67 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/uminus.m @@ -0,0 +1,18 @@ +function t = uminus(t) +%UMINUS Unary minus (-) for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +t.data = -t.data; diff --git a/external/tensor_toolbox_2.5/@tensor/uplus.m b/external/tensor_toolbox_2.5/@tensor/uplus.m new file mode 100755 index 0000000..cf6ac00 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/uplus.m @@ -0,0 +1,19 @@ +function t = uplus(t) +%UPLUS Unary plus (+) for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% This function does nothing! + diff --git a/external/tensor_toolbox_2.5/@tensor/xor.m b/external/tensor_toolbox_2.5/@tensor/xor.m new file mode 100755 index 0000000..ed2e1b8 --- /dev/null +++ b/external/tensor_toolbox_2.5/@tensor/xor.m @@ -0,0 +1,18 @@ +function Z = xor(X,Y) +%XOR Logical EXCLUSIVE OR for tensors. +% +% See also TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Z = tenfun(@xor,X,Y); diff --git a/external/tensor_toolbox_2.5/@ttensor/Contents.m b/external/tensor_toolbox_2.5/@ttensor/Contents.m new file mode 100755 index 0000000..7675604 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/Contents.m @@ -0,0 +1,24 @@ +% @TTENSOR +% +% Files +% disp - Command window display of a ttensor. +% display - Command window display of a ttensor. +% double - Convert ttensor to double array. +% end - Last index of indexing expression for ttensor. +% full - Convert a ttensor to a (dense) tensor. +% innerprod - Efficient inner product with a ttensor. +% isequal - True if each component of two ttensor's is numerically equal. +% mtimes - Implement scalar multiplication for a ttensor. +% mttkrp - Matricized tensor times Khatri-Rao product for ttensor. +% ndims - Return the number of dimensions for a ttensor. +% norm - Norm of a ttensor. +% nvecs - Compute the leading mode-n vectors for a ttensor. +% permute - Permute dimensions for a ttensor. +% size - Size of a ttensor. +% subsasgn - Subscripted reference for a ttensor. +% subsref - Subscripted reference for a ttensor. +% ttensor - Tensor stored as a Tucker operator (decomposed). +% ttm - Tensor times matrix for ttensor. +% ttv - Tensor times vector for ttensor. +% uminus - Unary minus for ttensor. +% uplus - Unary plus for ttensor. diff --git a/external/tensor_toolbox_2.5/@ttensor/disp.m b/external/tensor_toolbox_2.5/@ttensor/disp.m new file mode 100755 index 0000000..eec4572 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/disp.m @@ -0,0 +1,35 @@ +function disp(t,name) +%DISP Command window display of a ttensor. +% +% DISP(T) displays a ttensor with no name. +% +% DISP(T,NAME) display a ttensor with the given name. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: disp.m,v 1.14 2010/03/19 23:46:31 tgkolda Exp $ + +if ~exist('name','var') + name = 'ans'; +end + +fprintf(1,'%s is a ttensor of size %s\n', name, tt_size2str(size(t))); +disp(t.core, sprintf('\t%s.core',name)); + +for j = 1 : ndims(t) + fprintf('\t%s.U{%d} = \n', name, j); + output = tt_matrix2cellstr(t.u{j}); + fprintf('\t\t%s\n',output{:}); +end + + diff --git a/external/tensor_toolbox_2.5/@ttensor/display.m b/external/tensor_toolbox_2.5/@ttensor/display.m new file mode 100755 index 0000000..466a4b7 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/display.m @@ -0,0 +1,18 @@ +function display(t) +%DISPLAY Command window display of a ttensor. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: display.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + +disp(t,inputname(1)); diff --git a/external/tensor_toolbox_2.5/@ttensor/double.m b/external/tensor_toolbox_2.5/@ttensor/double.m new file mode 100755 index 0000000..ac634e8 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/double.m @@ -0,0 +1,20 @@ +function A = double(T) +%DOUBLE Convert ttensor to double array. +% +% A = double(T) converts T to a standard multidimensional array. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: double.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + +A = double(full(T)); diff --git a/external/tensor_toolbox_2.5/@ttensor/end.m b/external/tensor_toolbox_2.5/@ttensor/end.m new file mode 100755 index 0000000..c1215f7 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/end.m @@ -0,0 +1,23 @@ +function e = end(X,k,n) +%END Last index of indexing expression for ttensor. +% +% The expression X(end,:,:) will call END(X,1,3) to determine +% the value of the first index. +% +% See also TTENSOR, TTENSOR/SUBSREF, END. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: end.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + +% Note that this only works with {} because () is not supported by +% subsref. +e = ndims(X); diff --git a/external/tensor_toolbox_2.5/@ttensor/full.m b/external/tensor_toolbox_2.5/@ttensor/full.m new file mode 100755 index 0000000..99d0f9a --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/full.m @@ -0,0 +1,30 @@ +function X = full(T) +%FULL Convert a ttensor to a (dense) tensor. +% +% X = FULL(T) converts ttensor T to (dense) tensor X. +% +% See also TTENSOR, TENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: full.m,v 1.11 2010/03/19 23:46:31 tgkolda Exp $ + +% Preallocate to ensure there is enough space +X = tenzeros(size(T)); + +% Now do the calculation +X = ttm(T.core,T.u); + +% Make sure that X is a dense tensor (small chance it could be a sparse +% tensor). +X = tensor(X); + +return; diff --git a/external/tensor_toolbox_2.5/@ttensor/innerprod.m b/external/tensor_toolbox_2.5/@ttensor/innerprod.m new file mode 100755 index 0000000..a7b82a0 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/innerprod.m @@ -0,0 +1,68 @@ +function res = innerprod(X,Y) +%INNERPROD Efficient inner product with a ttensor. +% +% R = INNERPROD(X,Y) efficiently computes the inner product between +% two tensors X and Y. If Y is a tensor or sptensor, the inner +% product is computed directly and the computational complexity +% is... If Y is a ktensor, the inner product method for that type +% of tensor is called. +% +% See also TTENSOR, KTENSOR/INNERPROD +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: innerprod.m,v 1.13 2010/03/19 23:46:31 tgkolda Exp $ + +% X is a ttensor +switch class(Y) + + case {'ttensor'} + if ~isequal(size(X),size(Y)) + error('X and Y must be the same size.'); + end + if prod(size(X.core)) > prod(size(Y.core)) + % Reverse argument and call this function again so that the + % tensor with the smaller core is the first argument. + res = innerprod(Y,X); + return + end + W = cell(ndims(X),1); + for n = 1:ndims(X) + W{n} = X.u{n}'*Y.u{n}; + end + J = ttm(Y.core, W); + res = innerprod(X.core,J); + return + + case {'tensor','sptensor'} + if ~isequal(size(X),size(Y)) + error('X and Y must be the same size.'); + end + if (prod(size(X)) < prod(size(X.core))) + Z = full(X); + res = innerprod(Z,Y); + return; + end + Z = ttm(Y,X.u,'t'); + res = innerprod(Z, X.core); + return + + case {'ktensor'} + % Reverse arguments to call ktensor implementation + res = innerprod(Y,X); + return + + otherwise + disp(['Inner product not available for class ' class(Y)]); + return +end + + diff --git a/external/tensor_toolbox_2.5/@ttensor/isequal.m b/external/tensor_toolbox_2.5/@ttensor/isequal.m new file mode 100755 index 0000000..5cacf7a --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/isequal.m @@ -0,0 +1,19 @@ +function [tf, tf_core, tf_U] = isequal(A,B) +%ISEQUAL True if each component of two ttensor's is numerically equal. + +tf = false; +tf_core = false; +tf_U = false; + +if ~isa(B,'ttensor') + return; +end + +if ndims(A) ~= ndims(B) + return; +end + +tf_core = isequal(A.core, B.core); +tf_U = cellfun(@isequal, A.u, B.u); +tf = tf_core & all(tf_U); + diff --git a/external/tensor_toolbox_2.5/@ttensor/mtimes.m b/external/tensor_toolbox_2.5/@ttensor/mtimes.m new file mode 100755 index 0000000..65c629d --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/mtimes.m @@ -0,0 +1,24 @@ +function C = mtimes(A,B) +%MTIMES Implement scalar multiplication for a ttensor. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: mtimes.m,v 1.8 2010/03/19 23:46:31 tgkolda Exp $ + +if ~isa(B,'ttensor') && numel(B) == 1 + C = ttensor(B * A.core, A.u); +elseif ~isa(A,'ttensor') && numel(A) == 1 + C = ttensor(A * B.core, B.u); +else + error('Use mtimes(full(A),full(B)).'); +end diff --git a/external/tensor_toolbox_2.5/@ttensor/mttkrp.m b/external/tensor_toolbox_2.5/@ttensor/mttkrp.m new file mode 100755 index 0000000..54f119d --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/mttkrp.m @@ -0,0 +1,40 @@ +function V = mttkrp(X,U,n) +%MTTKRP Matricized tensor times Khatri-Rao product for ttensor. +% +% V = MTTKRP(X,U,n) efficiently calculates the matrix product of the +% n-mode matricization of X with the Khatri-Rao product of all +% entries in U, a cell array of matrices, except the nth. How to +% most efficiently do this computation depends on the type of tensor +% involved. +% +% See also TTENSOR, TTENSOR/TTV +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: mttkrp.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + +N = ndims(X); + +if (n==1) + R = size(U{2},2); +else + R = size(U{1},2); +end + +% Compute cell array of weights to multiply into core +W = cell(N,1); +for i = [1:n-1,n+1:N] + W{i} = (X.u{i}' * U{i}); +end +Y = mttkrp(X.core,W,n); + +% Find each column of answer by multiplying columns of X.u{n} with weights +V = X.u{n} * Y; diff --git a/external/tensor_toolbox_2.5/@ttensor/ndims.m b/external/tensor_toolbox_2.5/@ttensor/ndims.m new file mode 100755 index 0000000..d144c1a --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/ndims.m @@ -0,0 +1,20 @@ +function n = ndims(t) +%NDIMS Return the number of dimensions for a ttensor. +% +% NDIMS(T) returns the number of dimensions of tensor T. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: ndims.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + +n = numel(t.u); diff --git a/external/tensor_toolbox_2.5/@ttensor/norm.m b/external/tensor_toolbox_2.5/@ttensor/norm.m new file mode 100755 index 0000000..8ecb2bb --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/norm.m @@ -0,0 +1,29 @@ +function nrm = norm(X) +%NORM Norm of a ttensor. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: norm.m,v 1.9 2010/03/19 23:46:31 tgkolda Exp $ + + +if prod(size(X)) > prod(size(X.core)) + V = cell(ndims(X),1); + for n = 1:ndims(X) + V{n} = X.u{n}'*X.u{n}; + end + Y = ttm(X.core,V); + tmp = innerprod(Y, X.core); + nrm = sqrt(tmp); +else + nrm = norm(full(X)); +end diff --git a/external/tensor_toolbox_2.5/@ttensor/nvecs.m b/external/tensor_toolbox_2.5/@ttensor/nvecs.m new file mode 100755 index 0000000..6de712c --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/nvecs.m @@ -0,0 +1,85 @@ +function u = nvecs(X,n,r,opts) +%NVECS Compute the leading mode-n vectors for a ttensor. +% +% U = NVECS(X,n,r) computes the r leading eigenvalues of Xn*Xn' +% (where Xn is the mode-n matricization of X), which provides +% information about the mode-n fibers. In two-dimensions, the r +% leading mode-1 vectors are the same as the r left singular vectors +% and the r leading mode-2 vectors are the same as the r right +% singular vectors. +% +% U = NVECS(X,n,r,OPTS) specifies options: +% OPTS.eigsopts: options passed to the EIGS routine [struct('disp',0)] +% OPTS.flipsign: make each column's largest element positive [true] +% +% See also TTENSOR, TENMAT, EIGS. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: nvecs.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + +if ~exist('opts','var') + opts = struct; +end + +if isfield(opts,'eigsopts') + eigsopts = opts.eigsopts; +else + eigsopts.disp = 0; +end + +% Compute inner product of all n-1 factors +V = cell(ndims(X),1); +for i = 1:ndims(X) + if i == n, + V{i} = X.u{i}; + else + V{i} = X.u{i}' * X.u{i}; + end +end + +% Form H +H = ttm(X.core,V); + +if isa(H,'sptensor') + HnT = double(sptenmat(H,n,'t')); +else + H = full(H); + HnT = double(tenmat(H,n,'t')); +end +G = X.core; +if isa(G,'sptensor') + GnT = double(sptenmat(G,n,'t')); +else + G = full(G); + GnT = double(tenmat(G,n,'t')); +end + +% Compute Xn * Xn' +Y = HnT'*GnT*X.u{n}'; + +[u,d] = eigs(Y, r, 'LM', eigsopts); + +if isfield(opts,'flipsign') + flipsign = opts.flipsign; +else + flipsign = true; +end + +if flipsign + % Make the largest magnitude element be positive + [val,loc] = max(abs(u)); + for i = 1:r + if u(loc(i),i) < 0 + u(:,i) = u(:,i) * -1; + end + end +end diff --git a/external/tensor_toolbox_2.5/@ttensor/permute.m b/external/tensor_toolbox_2.5/@ttensor/permute.m new file mode 100755 index 0000000..82c4b90 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/permute.m @@ -0,0 +1,36 @@ +function b = permute(a,order) +%PERMUTE Permute dimensions for a ttensor. +% +% Y = PERMUTE(X,ORDER) rearranges the dimensions of X so that they +% are in the order specified by the vector ORDER. The tensor +% produced has the same values of X but the order of the subscripts +% needed to access any particular element are rearranged as +% specified by ORDER. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: permute.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + +N = ndims(a); + +if ~isequal(1:N,sort(order)) + error('Invalid permuation'); +end + +newcore = permute(a.core,order); +newu = a.u(order); +b = ttensor(newcore,newu); + + + + diff --git a/external/tensor_toolbox_2.5/@ttensor/size.m b/external/tensor_toolbox_2.5/@ttensor/size.m new file mode 100755 index 0000000..41ea26d --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/size.m @@ -0,0 +1,33 @@ +function m = size(t,idx) +%SIZE Size of a ttensor. +% +% D = SIZE(T) returns the size of the tensor. +% +% I = size(T,DIM) returns the size of the dimension specified by +% the scalar DIM. +% +% See also TTENSOR, TTENSOR/NDIMS. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: size.m,v 1.8 2010/03/19 23:46:31 tgkolda Exp $ + +if ndims(t) == 0 + m = []; +end + +if exist('idx','var') + m = size(t.u{idx}, 1); +else + for i = 1 : ndims(t) + m(i) = size(t.u{i}, 1); + end +end diff --git a/external/tensor_toolbox_2.5/@ttensor/subsasgn.m b/external/tensor_toolbox_2.5/@ttensor/subsasgn.m new file mode 100755 index 0000000..1f82e67 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/subsasgn.m @@ -0,0 +1,49 @@ +function t = subsasgn(t,s,b) +%SUBSASGN Subscripted reference for a ttensor. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: subsasgn.m,v 1.9 2010/03/19 23:46:31 tgkolda Exp $ + +switch s(1).type + case '.' + switch s(1).subs + case {'core','lambda'} + if length(s) == 1 + t = ttensor(b, t.u); + else + tmpcore = subsasgn(t.core, s(2:end), b); + t = ttensor(tmpcore, t.u); + end + case {'u','U'} + if length(s) == 1 + t = ttensor(t.core, b); + else + tmpu = subsasgn(t.u, s(2:end), b); + t = ttensor(t.core, tmpu); + end + otherwise + error(['Cannot change field ', s.subs, ' directly.']); + end + case '()' + error('Cannot change individual entries in ttensor.') + case '{}' + new_s(1).type = '.'; + new_s(1).subs = 'u'; + new_s(2:length(s)+1) = s; + t = subsasgn(t, new_s, b); + otherwise + error('Invalid subsasgn.'); +end + + diff --git a/external/tensor_toolbox_2.5/@ttensor/subsref.m b/external/tensor_toolbox_2.5/@ttensor/subsref.m new file mode 100755 index 0000000..5b63fa9 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/subsref.m @@ -0,0 +1,44 @@ +function a = subsref(t,s) +%SUBSREF Subscripted reference for a ttensor. +% +% Examples +% core = tensor(rand(2,2,2)); +% X = TTENSOR(core, rand{4,2), rand(5,2),rand(3,2)); +% X.core %<-- returns core array +% X.U %<-- returns a cell array of three matrices +% X.U{1} %<-- returns the matrix corresponding to the first mode. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: subsref.m,v 1.10 2010/03/19 23:46:31 tgkolda Exp $ + +switch s(1).type + case '.' + switch s(1).subs + case {'core','lambda'} + a = tt_subsubsref(t.core,s); + case {'U','u'} + a = tt_subsubsref(t.u,s); + otherwise + error(['No such field: ', s.subs]); + end + case '()' + error('Subsref with () not supported for ttensor.'); + case '{}' + new_s(1).type = '.'; + new_s(1).subs = 'u'; + new_s(2:length(s)+1) = s; + a = subsref(t, new_s); + otherwise + error('Invalid subsref.'); +end diff --git a/external/tensor_toolbox_2.5/@ttensor/ttensor.m b/external/tensor_toolbox_2.5/@ttensor/ttensor.m new file mode 100755 index 0000000..77ee1d5 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/ttensor.m @@ -0,0 +1,92 @@ +function t = ttensor(varargin) +%TTENSOR Tensor stored as a Tucker operator (decomposed). +% +% T = TTENSOR(G,U1,U2,...,UM) creates a TUCKER tensor from its +% constituent parts. Here G is a tensor of size K1 x K2 x ... x KM +% and each Um is a matrix with Km columns. +% +% T = TTENSOR(G,U) is the same as above except that U is a cell +% array containing matrix Um in cell m. +% +% The core tensor G can be any type of tensor that supports the +% following functions: +% - size +% - uminus +% - disp (with 2 arguments; see, e.g., TENSOR/DISP) +% - ttv +% - ttm +% - mtimes (scalar multiplication only) +% - permute +% - subsasgn +% - subsref +% +% T = TTENSOR(S) creates a TUCKER tensor by copying an existing +% TUCKER tensor. +% +% T = TTENSOR is the empty constructor. +% +% See also TENSOR, KTENSOR +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: ttensor.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + +% Empty constructor +if (nargin == 0) + t.core = tensor; % empty tensor + t.u = []; + t = class(t, 'ttensor'); + return; +end + +% Copy CONSTRUCTOR +if (nargin == 1) && isa(varargin{1}, 'ttensor') + t.core = varargin{1}.core; + t.u = varargin{1}.u; + t = class(t, 'ttensor'); + return; +end + +% Core can be basically anything that supports certain functions. +t.core = varargin{1}; + +if isa(varargin{2},'cell') + t.u = varargin{2}; +else + for i = 2 : nargin + t.u{i-1} = varargin{i}; + end +end + +% Check that each Um is indeed a matrix +for i = 1 : length(t.u) + if ndims(t.u{i}) ~= 2 + error(['Matrix U' int2str(i) ' is not a matrix!']); + end +end + +% Size error checking +k = size(t.core); + +if length(k) ~= length(t.u) + error(['CORE has order ', int2str(length(k)), ... + ' but there are ', int2str(length(t.u)), ' matrices.']); +end + +for i = 1 : length(t.u) + if size(t.u{i},2) ~= k(i) + error(['Matrix U' int2str(i) ' does not have ' int2str(k(i)) ... + ' columns.']); + end +end + +t = class(t, 'ttensor'); +return; diff --git a/external/tensor_toolbox_2.5/@ttensor/ttm.m b/external/tensor_toolbox_2.5/@ttensor/ttm.m new file mode 100755 index 0000000..0325d4e --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/ttm.m @@ -0,0 +1,107 @@ +function X = ttm(X,V,varargin) +%TTM Tensor times matrix for ttensor. +% +% Y = TTM(X,A,N) computes the n-mode product of the ttensor X with a +% matrix A; i.e., X x_N A. The integer N specifies the dimension +% (or mode) of X along which A should be multiplied. If size(A) = +% [J,I], then X must have size(X,N) = I. The result will be a +% ttensor of the same order and size as X except that size(Y,N) = J. +% +% Y = TTM(X,{A,B,C,...}) computes the n-mode product of the ttensor +% X with a sequence of matrices in the cell array. The n-mode +% products are computed sequentially along all dimensions (or modes) +% of X. The cell array contains ndims(X) matrices. +% +% Y = TTM(X,{A,B,C,...},DIMS) computes the sequence tensor-matrix +% products along the dimensions specified by DIMS. +% +% Y = TTM(...,'t') performs the same computations as above except +% the matrices are transposed. +% +% Examples +% X = ttensor(tensor(rand(2,2,2,2)),{rand(5,2),rand(3,2),rand(4,2),rand(2,2)}); +% A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2); +% Y = ttm(X, A, 1) %<-- computes X times A in mode-1 +% Y = ttm(X, {A,B,C,D}, 1) %<-- same as above +% Y = ttm(X, A', 1, 't') %<-- same as above +% Y = ttm(X, {A,B,C,D}, [1 2 3 4]) %<-- 4-way multiply +% Y = ttm(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above +% Y = ttm(X, {A,B,C,D}) %<-- same as above +% Y = ttm(X, {A',B',C',D'}, 't') %<-- same as above +% Y = ttm(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4 +% Y = ttm(X, {A,B,C,D}, [3 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, [1 2 4]) %<-- 3-way multiply +% Y = ttm(X, {A,B,C,D}, [1 2 4]) %<-- same as above +% Y = ttm(X, {A,B,D}, -3) %<-- same as above +% Y = ttm(X, {A,B,C,D}, -3) %<-- same as above +% +% See also TTENSOR, TTENSOR/ARRANGE, TENSOR/TTM +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: ttm.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + + +%%%%%%%%%%%%%%%%%%%%%% +%%% ERROR CHECKING %%% +%%%%%%%%%%%%%%%%%%%%%% + +% Check the number of arguments +if (nargin < 2) + error('TTM requires at least two arguments.'); +end + +% Check for transpose option +isTranspose = false; +if numel(varargin) > 0 + if isnumeric(varargin{1}); + dims = varargin{1}; + end + isTranspose = (ischar(varargin{end}) && (varargin{end} == 't')); +end + +% Check for dims argument +if ~exist('dims','var') + dims = []; +end + +% Check that 2nd argument is cell array. If not, recall with V as a +% cell array with one element. +if ~iscell(V) + X = ttm(X,{V},dims,varargin{end}); + return; +end + +% Get sorted dims and index for multiplicands +[dims,vidx] = tt_dimscheck(dims,ndims(X),numel(V)); + +% Determine correct size index +if isTranspose + j = 1; +else + j = 2; +end + +% Check that each multiplicand is the right size. +for i = 1:numel(dims) + if (ndims(V) ~= 2) || (size(V{vidx(i)},j) ~= size(X,dims(i))) + error('Multiplicand is wrong size'); + end +end + +% Do the multiplications in the specified modes. +for i = 1:numel(dims) + if isTranspose + X.u{dims(i)} = V{vidx(i)}'* X.u{dims(i)}; + else + X.u{dims(i)} = V{vidx(i)} * X.u{dims(i)}; + end +end diff --git a/external/tensor_toolbox_2.5/@ttensor/ttv.m b/external/tensor_toolbox_2.5/@ttensor/ttv.m new file mode 100755 index 0000000..941fbbd --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/ttv.m @@ -0,0 +1,81 @@ +function c = ttv(a,v,dims) +%TTV Tensor times vector for ttensor. +% +% Y = TTV(X,A,N) computes the product of ttensor X with a +% (column) vector A. The integer N specifies the dimension in X +% along which A is multiplied. If size(A) = [I,1], then X must have +% size(X,N) = I. Note that ndims(Y) = ndims(X) - 1 because the N-th +% dimension is removed. +% +% Y = TTV(X,{A1,A2,...}) computes the product of ttensor X with a +% sequence of vectors in the cell array. The products are computed +% sequentially along all dimensions (or modes) of X. The cell array +% contains ndims(X) vectors. +% +% Y = TTV(X,{A1,A2,...},DIMS) computes the sequence tensor-vector +% products along the dimensions specified by DIMS. +% +% See also TENSOR/TTV, TTENSOR, TTENSOR/TTM. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: ttv.m,v 1.6 2010/03/19 23:46:31 tgkolda Exp $ + + +%%%%%%%%%%%%%%%%%%%%%% +%%% ERROR CHECKING %%% +%%%%%%%%%%%%%%%%%%%%%% + +% Check the number of arguments +if (nargin < 2) + error('TTV requires at least two arguments.'); +end + +% Check for 3rd argument +if ~exist('dims','var') + dims = []; +end + +% Check that 2nd argument is cell array. If not, recall with v as a +% cell array with one element. +if ~iscell(v) + c = ttv(a,{v},dims); + return; +end + +% Get sorted dims and index for multiplicands +[dims,vidx] = tt_dimscheck(dims,ndims(a),numel(v)); + +% Check that each multiplicand is the right size. +for i = 1:numel(dims) + if ~isequal(size(v{vidx(i)}),[size(a,dims(i)) 1]) + error('Multiplicand is wrong size'); + end +end + +% Figure out which dimensions will be left when we're done +remdims = setdiff(1:ndims(a),dims); + +% Create w to be multiplied with a.core +w = cell(ndims(a),1); +for i = 1:numel(dims) + w{dims(i)} = a.u{dims(i)}' * v{vidx(i)}; +end + +% Create new core +newcore = ttv(a.core,w,dims); + +% Create final result +if isempty(remdims) + c = newcore; +else + c = ttensor(newcore,a.u{remdims}); +end diff --git a/external/tensor_toolbox_2.5/@ttensor/uminus.m b/external/tensor_toolbox_2.5/@ttensor/uminus.m new file mode 100755 index 0000000..1a756da --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/uminus.m @@ -0,0 +1,18 @@ +function t = uminus(t) +%UMINUS Unary minus for ttensor. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: uminus.m,v 1.8 2010/03/19 23:46:31 tgkolda Exp $ + +t.core = -t.core; diff --git a/external/tensor_toolbox_2.5/@ttensor/uplus.m b/external/tensor_toolbox_2.5/@ttensor/uplus.m new file mode 100755 index 0000000..dad0c78 --- /dev/null +++ b/external/tensor_toolbox_2.5/@ttensor/uplus.m @@ -0,0 +1,18 @@ +function t = uplus(t) +%UPLUS Unary plus for ttensor. +% +% See also TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2010, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. +% http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2010) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in tensor_toolbox/LICENSE.txt +% $Id: uplus.m,v 1.7 2010/03/19 23:46:31 tgkolda Exp $ + +% This function does nothing! diff --git a/external/tensor_toolbox_2.5/COPYRIGHT.txt b/external/tensor_toolbox_2.5/COPYRIGHT.txt new file mode 100755 index 0000000..7d729fe --- /dev/null +++ b/external/tensor_toolbox_2.5/COPYRIGHT.txt @@ -0,0 +1,35 @@ +Copyright + +Copyright (2012) Sandia Corporation. Under the terms of Contract +DE-AC04-94AL85000, there is a non-exclusive license for use of this +work by or on behalf of the U.S. Government. Export of this data may +require a license from the United States Government. + +Notice + +For five (5) years from 01/30/2012, the United States Government is +granted for itself and others acting on its behalf a paid-up, +nonexclusive, irrevocable worldwide license in this data to reproduce, +prepare derivative works, and perform publicly and display publicly, +by or on behalf of the Government. There is provision for the possible +extension of the term of this license. Subsequent to that period or +any extension granted, the United States Government is granted for +itself and others acting on its behalf a paid-up, nonexclusive, +irrevocable worldwide license in this data to reproduce, prepare +derivative works, distribute copies to the public, perform publicly +and display publicly, and to permit others to do so. The specific term +of the license can be identified by inquiry made to Sandia Corporation +or DOE. + +NEITHER THE UNITED STATES GOVERNMENT, NOR THE UNITED STATES DEPARTMENT +OF ENERGY, NOR SANDIA CORPORATION, NOR ANY OF THEIR EMPLOYEES, MAKES +ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL RESPONSIBILITY +FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF ANY INFORMATION, +APPARATUS, PRODUCT, OR PROCESS DISCLOSED, OR REPRESENTS THAT ITS USE +WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS. + +Any licensee of This software has the obligation and responsibility to +abide by the applicable export control laws, regulations, and general +prohibitions relating to the export of technical data. Failure to +obtain an export control license or other authority from the +Government may result in criminal liability under U.S. laws. diff --git a/external/tensor_toolbox_2.5/Contents.m b/external/tensor_toolbox_2.5/Contents.m new file mode 100755 index 0000000..4cf4e6e --- /dev/null +++ b/external/tensor_toolbox_2.5/Contents.m @@ -0,0 +1,235 @@ +% Tensor Toolbox (Sandia National Labs) +% Version 2.5 01-FEB-2012 +% +% Tensor Toolbox for dense, sparse, and decomposed n-way arrays. +% +% cp_als - Compute a CP decomposition of any type of tensor. +% cp_apr - Compute nonnegative CP with alternating Poisson regression. +% cp_nmu - Compute nonnegative CP with multiplicative updates. +% cp_opt - Fits a CP model to a tensor via optimization. +% cp_wopt - Fits a weighted CP model to a tensor via optimization. +% create_guess - Creates initial guess for CP or Tucker fitting. +% create_problem - Create test problems for tensor factorizations. +% export_data - Export tensor-related data to a file. +% import_data - Import tensor-related data to a file. +% khatrirao - Khatri-Rao product of matrices. +% parafac_als - Deprecated. Use CP_ALS instead. +% sptendiag - Creates a sparse tensor with v on the diagonal. +% sptenrand - Sparse uniformly distributed random tensor. +% sshopm - Shifted power method for finding a real eigenpair of a real tensor. +% sshopmc - Shifted power method for real/complex eigenpair of a real tensor. +% tendiag - Creates a tensor with v on the diagonal. +% teneye - Create identity tensor of specified size. +% tenones - Ones tensor. +% tenrand - Uniformly distributed pseudo-random tensor. +% tenzeros - Create zeros tensor. +% tucker_als - Higher-order orthogonal iteration. +% +% @TENSOR +% and - Logical AND (&) for tensors. +% collapse - Collapse tensor along specified dimensions. +% contract - Contract tensor along two dimensions (array trace). +% ctranspose - is not defined for tensors. +% disp - Command window display of a tensor. +% display - Command window display of a tensor. +% double - Convert tensor to double array. +% end - Last index of indexing expression for tensor. +% eq - Equal (==) for tensors. +% find - Find subscripts of nonzero elements in a tensor. +% full - Convert to a (dense) tensor. +% ge - Greater than or equal (>=) for tensors. +% gt - Greater than (>) for tensors. +% innerprod - Efficient inner product with a tensor. +% isequal - for tensors. +% issymmetric - Verify that a tensor X is symmetric in specified modes. +% ldivide - Left array divide for tensor. +% le - Less than or equal (<=) for tensor. +% lt - Less than (<) for tensor. +% minus - Binary subtraction (-) for tensors. +% mldivide - Slash left division for tensors. +% mrdivide - Slash right division for tensors. +% mtimes - tensor-scalar multiplication. +% mttkrp - Matricized tensor times Khatri-Rao product for tensor. +% ndims - Return the number of dimensions of a tensor. +% ne - Not equal (~=) for tensors. +% nnz - Number of nonzeros for tensors. +% norm - Frobenius norm of a tensor. +% not - Logical NOT (~) for tensors. +% nvecs - Compute the leading mode-n vectors for a tensor. +% or - Logical OR (|) for tensors. +% permute - Permute tensor dimensions. +% plus - Binary addition (+) for tensors. +% power - Elementwise power (.^) operator for a tensor. +% rdivide - Right array divide for tensors. +% reshape - Change tensor size. +% scale - Scale along specified dimensions of tensor. +% size - Tensor dimensions. +% squeeze - Remove singleton dimensions from a tensor. +% subsasgn - Subscripted assignment for a tensor. +% subsref - Subscripted reference for tensors. +% symmetrize - Symmetrize a tensor X in specified modes. +% tenfun - Apply a function to each element in a tensor. +% tensor - Create tensor. +% times - Array multiplication for tensors. +% transpose - is not defined on tensors. +% ttm - Tensor times matrix. +% ttsv - Tensor times same vector in multiple modes. +% ttt - Tensor mulitplication (tensor times tensor). +% ttv - Tensor times vector. +% uminus - Unary minus (-) for tensors. +% uplus - Unary plus (+) for tensors. +% xor - Logical EXCLUSIVE OR for tensors. +% +% @SPTENSOR +% and - Logical AND (&) for sptensors. +% collapse - Collapse sparse tensor along specified dimensions. +% contract - Contract sparse tensor along two dimensions (array trace). +% ctranspose - is not defined for sparse tensors. +% disp - Command window display of a sparse tensor. +% display - Command window display of a sparse tensor. +% divide - Divide an SPTENSOR by a nonnegative KTENSOR. +% double - Converts a sparse tensor to a dense multidimensional array. +% elemfun - Manipulate the nonzero elements of a sparse tensor. +% end - Last index of indexing expression for sparse tensor. +% eq - Equal (==) for sptensors. +% find - Find subscripts of nonzero elements in a sparse tensor. +% full - Convert a sparse tensor to a (dense) tensor. +% ge - Greater than or equal for sptensors. +% gt - Greater than for sptensors. +% innerprod - Efficient inner product with a sparse tensor. +% isequal - for sptensors. +% ldivide - Array right division for sparse tensors. +% le - Less than or equal for sptensors. +% lt - Less than for sptensors. +% minus - Binary subtraction for sparse tensors. +% mldivide - Slash left division for sparse tensors. +% mrdivide - Slash right division for sparse tensors. +% mtimes - sptensor-scalar multiplication. +% mttkrp - Matricized tensor times Khatri-Rao product for sparse tensor. +% ndims - Number of dimensions of a sparse tensor. +% ne - Not equal (~=) for sptensors. +% nnz - Number of nonzeros in sparse tensor. +% norm - Frobenius norm of a sparse tensor. +% not - Logical NOT (~) for sptensors. +% nvecs - Compute the leading mode-n vectors for a sparse tensor. +% ones - Replace nonzero elements of sparse tensor with ones. +% or - Logical OR (|) for sptensors. +% permute - Rearrange the dimensions of a sparse tensor. +% plus - Binary addition for sparse tensors. +% rdivide - Array right division for sparse tensors. +% reshape - Reshape sparse tensor. +% scale - Scale along specified dimensions for sparse tensors. +% size - Sparse tensor dimensions. +% spmatrix - Converts a two-way sparse tensor to sparse matrix. +% sptensor - Create a sparse tensor. +% squeeze - Remove singleton dimensions from a sparse tensor. +% subsasgn - Subscripted assignment for sparse tensor. +% subsref - Subscripted reference for a sparse tensor. +% times - Array multiplication for sparse tensors. +% transpose - is not defined on sparse tensors. +% ttm - Sparse tensor times matrix. +% ttt - Sparse tensor times sparse tensor. +% ttv - Sparse tensor times vector. +% uminus - Unary minus (-) for sptensor. +% uplus - Unary plus (+) for sptensor. +% xor - Logical XOR for sptensors. +% +% @TTENSOR +% disp - Command window display of a ttensor. +% display - Command window display of a ttensor. +% double - Convert ttensor to double array. +% end - Last index of indexing expression for ttensor. +% full - Convert a ttensor to a (dense) tensor. +% innerprod - Efficient inner product with a ttensor. +% isequal - True if each component of two ttensor's is numerically equal. +% mtimes - Implement scalar multiplication for a ttensor. +% mttkrp - Matricized tensor times Khatri-Rao product for ttensor. +% ndims - Return the number of dimensions for a ttensor. +% norm - Norm of a ttensor. +% nvecs - Compute the leading mode-n vectors for a ttensor. +% permute - Permute dimensions for a ttensor. +% size - Size of a ttensor. +% subsasgn - Subscripted reference for a ttensor. +% subsref - Subscripted reference for a ttensor. +% ttensor - Tensor stored as a Tucker operator (decomposed). +% ttm - Tensor times matrix for ttensor. +% ttv - Tensor times vector for ttensor. +% uminus - Unary minus for ttensor. +% uplus - Unary plus for ttensor. +% +% @KTENSOR +% arrange - Arranges the rank-1 components of a ktensor. +% datadisp - Special display of a ktensor. +% disp - Command window display for a ktensor. +% display - Command window display for a ktensor. +% double - Convert a ktensor to a double array. +% end - Last index of indexing expression for ktensor. +% extract - Creates a new ktensor with only the specified components. +% fixsigns - Fix sign ambiguity of a ktensor. +% full - Convert a ktensor to a (dense) tensor. +% innerprod - Efficient inner product with a ktensor. +% isequal - True if each component of two ktensor's is numerically equal. +% ktensor - Tensor stored as a Kruskal operator (decomposed). +% minus - Binary subtraction for ktensor. +% mtimes - Implement A*B (scalar multiply) for ktensor. +% mttkrp - Matricized tensor times Khatri-Rao product for ktensor. +% ncomponents - Number of components for a ktensor. +% ndims - Number of dimensions for a ktensor. +% norm - Frobenius norm of a ktensor. +% normalize - Normalizes the columns of the factor matrices. +% nvecs - Compute the leading mode-n vectors for a ktensor. +% permute - Permute dimensions of a ktensor. +% plus - Binary addition for ktensor. +% redistribute - Distribute lambda values to a specified mode. +% score - Checks if two ktensors match except for permutation. +% size - Size of ktensor. +% subsasgn - Subscripted assignement for ktensor. +% subsref - Subscripted reference for a ktensor. +% times - Element-wise multiplication for ktensor. +% tocell - Convert X to a cell array. +% ttm - Tensor times matrix for ktensor. +% ttv - Tensor times vector for ktensor. +% uminus - Unary minus for ktensor. +% uplus - Unary plus for a ktensor. +% +% @TENMAT +% ctranspose - Complex conjugate transpose for tenmat. +% disp - Command window display of a matricized tensor (tenmat). +% display - Command window display of a tenmat. +% double - Convert tenmat to double array. +% end - Last index of indexing expression for tenmat. +% minus - Binary subtraction (-) for tenmat. +% mtimes - Multiplies two tenmat objects. +% norm - Frobenius norm of a tenmat. +% plus - Binary addition (+) for tenmat. +% size - Size of tenmat. +% subsasgn - Subscripted assignment for tenmat. +% subsref - Subscripted reference for tenmat. +% tenmat - Create a matricized tensor. +% tsize - Tensor size of tenmat. +% uminus - Unary minus (-) for tenmat. +% uplus - Unary plus (+) for tenmat. +% +% @SPTENMAT +% aatx - Implicitly compute A * A' * x for sptenmat. +% disp - Command window display of a sptenmat. +% display - Command window display of a sptenmat. +% double - Convert a sptenmat to a sparse matrix. +% end - Last index of indexing expression for sptenmat. +% full - Convert a sptenmat to a (dense) tenmat. +% nnz - Return number of nonzeros in a sptenmat. +% norm - Frobenius norm of a sptenmat. +% size - Return size of sptenmat. +% sptenmat - Matricized sparse tensor stored as a sparse 2D array. +% subsasgn - Subscripted assignment for sptenmat. +% subsref - Subscripted reference for a sptenmat. +% tsize - Tensor size of sptenmat. +% uminus - Unary minus (-) for sptenmat. +% uplus - Unary plus (+) for sptenmat. +% +% MET +% ttm_me - Memory-efficient sptensor times matrix. +% ttm_me_mem - Estimates intermediate memory comsumption for ttm_me. +% ttm_me_partition - Finds best order for ttm_me. +% tucker_me - Memory-efficient Tucker higher-order orthogonal iteration. +% tucker_me_test - Very simple tests of tucker_me. diff --git a/external/tensor_toolbox_2.5/INSTALL.txt b/external/tensor_toolbox_2.5/INSTALL.txt new file mode 100755 index 0000000..ae6fd33 --- /dev/null +++ b/external/tensor_toolbox_2.5/INSTALL.txt @@ -0,0 +1,29 @@ +Please remember to cite the appropriate references when you have used +Tensor Toolbox in your work. See "How to Cite" under +http://www.sandia.gov/~tgkolda/TensorToolbox/ for more details. + +To install the Tensor Toolbox for MATLAB: + +1. Unpack the compressed file. In a linux environment, for example, this can + be done from the command line via: + + unzip tensor_toolbox_2.5.zip + + *or* + + gunzip -c tensor_toolbox_2.5.tar.gz | tar xvf - + + This should create a directory named *tensor_toolbox_2.5*. + +2. Rename the root directory from *tensor_toolbox_2.5* + to *tensor_toolbox*. + +3. Start MATLAB. + +4. Within MATLAB, cd to the *tensor_toolbox* directory and execute the + following commands: + + addpath(pwd) %<-- Add the tensor toolbox to the MATLAB path + cd ../met; addpath(pwd) %<-- [OPTIONAL] Also add the met directory + savepath %<-- Save for future MATLAB sessions + diff --git a/external/tensor_toolbox_2.5/LICENSE.txt b/external/tensor_toolbox_2.5/LICENSE.txt new file mode 100755 index 0000000..ea5828b --- /dev/null +++ b/external/tensor_toolbox_2.5/LICENSE.txt @@ -0,0 +1,94 @@ + Restricted Software License Agreement + +Sandia Corporation ("SANDIA"), under its Contract No. DE-AC04-94AL85000 +with the United States Department of Energy for the management and +operation of the Sandia National Laboratories, Livermore, California and +Albuquerque, New Mexico, has developed the MATLAB Tensor Toolbox, herein +called "TENSOR TOOLBOX". By downloading this software, the licensee +("YOU") agree to the following terms: + + 1. Grants + 1. Subject to the terms and conditions of this Agreement, + including Attachment A, YOU are granted a nontransferable, + nonexclusive right and license, without the right to + sublicense, to: use, modify, and/or make derivative works or + compilations of the TENSOR TOOLBOX for research and + evaluation purposes only. + 2. YOU agree that this restricted license does not allow YOU to + make any proprietary or commercial use of the TENSOR TOOLBOX + such as but not limited to the copying, distribution, + displaying, performing, manufacturing, selling, or offering + for sale of any product or service using the TENSOR TOOLBOX. + 3. YOU agree to give credit to the original authors (Brett W. + Bader and Tamara G. Kolda) at SANDIA in any work that + results from using the TENSOR TOOLBOX. + 4. If YOU intend to sell or offer for sale any portion of + TENSOR TOOLBOX or any modifications, derivative works, + compilations, products or services of the TENSOR TOOLBOX, + then YOU must obtain the appropriate license from SANDIA by + contacting Sandia Software Licensing Manager, Craig A. Smith + at +1 (925) 294-3358. + 2. Reproduction and Distribution + 1. YOU agree not to use the TENSOR TOOLBOX except as authorized + herein, and that YOU will not make, have made, or permit to + be made, any copies of the TENSOR TOOLBOX, except to be used + within your own facilities for research and evaluation + purposes. + 2. YOU agree to have other users download the TENSOR TOOLBOX + from its distribution web site, currently + http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. + 3. Disclaimer + 1. NEITHER SANDIA, THE UNITED STATES NOR THE UNITED STATES + DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES MAKES ANY + WARRANTY, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR + ASSUMES ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE + ACCURACY, COMPLETENESS, OR USEFULNESS OF ANY INFORMATION, + APPARATUS, PRODUCT, OR PROCESS OR REPRESENTS THAT ITS USE + WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, OR ASSUMES ANY + LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES RESULTING + FROM ITS USE BY ANYONE. + 2. The U.S. Government has a paid-up, nonexclusive, irrevocable + worldwide license in the TENSOR TOOLBOX to reproduce, + prepare derivative works, and perform publicly and display + publicly by or on behalf of the U.S. Government. + 3. The U.S. Government is neither a party to nor assumes + any liability for activities of the Contractor (SANDIA) in + connection with this License Agreement. + 4. Indemnity + 1. Except for negligent acts or omissions of SANDIA, if YOU, + your assignees or licensees, makes, uses or sells a product, + process or service that includes the TENSOR TOOLBOX, then + YOU shall indemnify SANDIA and the U.S. Government for all + damages, costs, and expenses, including attorneys' fees, + arising from personal injury or property damage occurring as + a result of making, using or selling the product or process. + 2. SANDIA warrants that the TENSOR TOOLBOX is an original work + of authorship owned or controlled by SANDIA. + 3. SANDIA warrants that it has the right to license copyrights + in the TENSOR TOOLBOX. + 5. Export Control Notice + 1. The export of articles and information from the U.S. may + require a government license; violators subject to criminal + penalties. + 6. No Waivers + 1. The failure of SANDIA, at any time, to exercise any right or + remedy of this Agreement shall not be construed to be a + waiver of such right or remedy nor preclude SANDIA from + exercising such right and remedy thereafter. + 7. Controlling Law + 1. This Agreement shall be construed according to the laws of + the State of California and the United States of America. + + + Attachment A + + 1. Tensor Toolbox + TENSOR TOOLBOX is a Sandia Corporation copyrighted software, SCR + #926, that provides a collection of MATLAB classes for tensor + manipulations that can be used for fast algorithm prototyping. + 2. License Fees: + TENSOR TOOLBOX is being offered at no cost under this agreement. + Commercial distribution licenses for TENSOR TOOLBOX are available + from Sandia at reasonable rates. + diff --git a/external/tensor_toolbox_2.5/RELEASE_NOTES.txt b/external/tensor_toolbox_2.5/RELEASE_NOTES.txt new file mode 100755 index 0000000..0cc917c --- /dev/null +++ b/external/tensor_toolbox_2.5/RELEASE_NOTES.txt @@ -0,0 +1,286 @@ +Tensor Toolbox version 2.5 +by Brett W. Bader, Tamara G. Kolda, Jimeng Sun, Evrim Acar, +Daniel M. Dunlavy, Eric C. Chi, Jackson Mayo, et al. +Copyright 2012, Sandia National Laboratories. +Released February 1, 2012 + +============================================ +Changes from Version 2.4 (March 22, 2010) +============================================ + +Top Level +- The "algorithms" directory has been eliminated. All routines are now + at the root level, meaning that only one directory has to be added + to the path to get all of Tensor Toolbox's standard functionality. +- Added new CREATE_PROBLEM and CREATE_GUESS routines that can be used + to generate test problems and initial guesses. These were first used + at the AIM 2010 Tensor Decomposition workshop. Added TT_RANDORTHMAT, + a helper function for creating problems. +- Added new SSHOPM and SSHOPMC code for Shifted Symmetric Higher-Order + Power Method for computing tensor eigenpairs. +- Added new CP_APR method for Poisson Tensor Factorization via + alternating Poisson regression, along with helper function + tt_loglikelihood. +- Added TENEYE to create "identity tensor". +- Helper functions for CP_OPT and CP_WOPT (like cp_fg) now have "tt_" + prepended to their names. They are not listed in the contents files. +- Adding ability to import and export text versions of matrices and + tensors via IMPORT_DATA/EXPORT_DATA functions. +- Making calling sequence to TENZEROS, TENRAND, and TENONES + consistent. Now all three will take either a size array or a list, + i.e., tenones([5 4 3]) or tenones(5,4,3) produce the same + results. Eliminated two-argument version of tenzeros, i.e., a call + to tenzeros(M,N) should be changed to tenzeros(N*ones(1,M)). +- Added additional comments in CP_ALS. +- Made output of CP_WOPT consistent with CP_OPT, i.e., now includes + output of optimization method. +- Fixed bug for empty tensor in TENONES. +- Fixed TT_IND2SUB, TT_SUB2IND to handle empty inputs. + +Documentation +- Added documentation in the help browser for cp_opt, cp_wopt, cp_als, + and sshopm. + +Class: tensor +- Added SYMMETRIZE function to symmetrize a tensor and ISSYMMETRIC + function to check if a tensor is symmetric. +- Adding new TTSV function to compute a tensor times the same vector + in every mode. Intended for symmetric tensors and doesn't allow user + to specify exactly which modes are skipped. +- Fixed "empty tensor" bugs in TENSOR (constructor), PERMUTE, COLLAPSE. +- Fixed "1D tensor" bug in TENMAT. +- Fixed bug with no results in FIND. +- More error checking in MTTKRP. + +CLASS: sptensor +- Added DIVIDE function for elementwise division. + +Class: ktensor +- Added new SCORE function to compute "factor match score" for + two ktensor's. Includes "greedy" option when +- Added new REDISTRIBUTE function to redistribute the weights from + lambda into a specified mode. +- Fixed bug in NORM, which sometimes returned a negative value due to + small errors in the calculation. Now it returns max(0,val). +- Added ISEQUAL function that checks for elementwise equality on + individual components. +- Lots of new options for the NORMALIZE function. + +Class: ttensor +- Added ISEQUAL function that checks for elementwise equality on + individual components. + +============================================ +Changes from Version 2.3 (July 8, 2009) +============================================ +General +- tenzeros(m,n): Now has the ability to create an mth-order tensor of + size n in every mode. tenzeros(siz) still works as usual. +- tt_subcheck now uses isfinite rather than ~isnan and ~isinf based on + error report from user. + +Algorithms +- Added new cp_opt and cp_wopt functions (and related utility + functions) for computing CP and weighted CP via optimization. + Requires that the user also install the Poblano Toolbox for + Matlab. This is freely available at + http://software.sandia.gov/trac/poblano. +- Changed the way that cp_als and tucker_als handle input arguments so + that they can now be parameter-value pairs. Should be backwards + compatible with old calling sequence. +- cp_als: Reverted the way that Unew is calculated from Unew = Unew * + pinv(Y) to Unew (Y \ Unew')'; which is from TTB2.2 and seems to give + better performance. + +Class: sptensor +- permute - Added check for empty tensor based on user error report. +- spmatrix - Added check for empty tensor based on user error report. +- sptensor - Replaced "~" with "junk" so it will work with Matlab 7.8 + (older version). Allowed sptensor to take an sptensor3 object + (though this class is not released yet) as input and convert it. + +Class: ktensor +- Revamped "arrange" so that it can also just accept a permutation and + rearrange the components. +- Adding a new "extract" function to select and extract a subset of the + components (rank-one factors) of a ktensor. +- Adding a new function "ncomponents" to return the number of + components. +- Added a "normalize" function that normalizes the columns of the factor + matrices to length 1 and absorbs the weights into lambda (without + rearranging the factors). +- Added new function "tocell" to convert a ktensor to a cell array. + +Class: sptenmat +- In function "double", added check for empty tensor based on error + report from user. + +============================================ +Changes from Version 2.2 (January 10, 2007) +============================================ +General: +- Added Memory Efficient Tucker (MET) package by Tamara Kolda and + Jimeng Sun. Type 'help tucker_me' after installation for more + information. +- Fixed bug in tenzeros command so that it now returns an empty tensor + when the initial size is emtpy. +- Fixed bug in tt_assignment_type so that it works with a sparse + tensor that is initially completely empty. +- Added comments to tt_sub2ind and tt_ind2sub. +- Removed errant ^M's at the end of every line of tt_subscheck. + +Algorithms: +- Changed parafac_als to cp_als (old one can still be called but is + deprecated). +- Added an option to cp_als to only print the information every n + iterations where n is a user-defined parameter. Also fixed bug in + the case of R=1. +- Added new cp_nmu function for computing a nonnegative tensor + factorization based upon Lee & Seung's NMF multiplicative update. +- Made calculation of residual in Tucker more efficient. + +Class: tensor +- Adds reshape command. +- Fixed find function so that it always returns a column vector. + (Bug# 3969) +- Fixed tenfun documentation. (Bug# 3339) + +Class: sptensor +- Adds reshape and spmatrix commands. +- Fixed bug in constructor so that it checks for subscripts out of + range and other input problems. (Bug# 3925) +- Fixed bug is subsasgn so that it works for a certain way of + inserting complex values. (Bug #3868) +- Fixed bug in disp function for sptensor that caused it not to accept + the user input to display all nonzeros for large tensors. (Bug #4009) +- Fixed bug in collapse so that it handles empty sptensor's correctly. +- Fixed bug in rdivide so that it will work correctly when either + argument is an empty tensor. +- Fixed bug in squeeze so that it now works correctly for sptensor's + with no nonzero elements. (Bug #3002) +- Fixed bug in subsasgn for a sptensor so that it works even when the + initial tensor is completely empty. +- Fixed bug in ttt so that it works even when one of the sptensors has + zero nonzeros. (Bug #3017) +- Fixed bug in elemfun that didn't remove those nonzeros that had + become zero (e.g., log 1 = 0). (Bug# 3235) + +Class: sptenmat +- Fixed bug in sptenmat so that it works when it is passed an sptensor + that doesn't have any entries. + +============================================ +Changes from Version 2.1 (December 1, 2006) +============================================ +General: +- Added INSTALL.txt with installation instructions. +- Updated copyright date from 2006 to 2007 throughout. + +Classes: tensor and sptensor +- Added transpose and ctranspose functions that throw an error + (transpose is not supported for tensors, but previously would do + nothing as if it *had* performed the transpose). +- Added ldivide, rdivide, lmdivide, and rmdivide, though they all work + only with scalars. + +Class: tensor +- Added isequal. +- Made find slightly more efficient in the case where the + corresponding values are not also returned. +- Fixed bug in assigning elements to 1-dimensional tensors. + +Class: sptensor +- Cleaner display with disp or display functions. +- Added checks against invalid sizes and subscripts for tensor + construction and subscripted reference and assignment. +- Fixed bug where the index 58 was confused with the character ':' + in subscripted reference and assignment. +- Made results of logical operators consistent with how sparse + matrices work, i.e., produces a dense tensor iff the equivalent + command on a sparse matrix would do the same. +- Plus and minus now work with a scalar or dense tensor, and the + result in those cases is dense. +- Added ability to do .* with a scalar. +- Made it so that isequal now works with dense tensors and will return + true if the two tensors are equivalent. +- Fixed bugs in double and squeeze on an all-zero sparse tensor. + +============================================ +Changes from Version 2.0 (September 6, 2006) +============================================ +All +- innerprod: Added checks that sizes match +- Improved subscripted assignment for tensor and sptensor. Now + supports assignment to a scalar (i.e., assign every element to that + scalar) and growth in both the size and number of dimensions. + +Class: tensor +- Added new function: nnz +- tenfun (and most relational operations): Fixed major bug is + dense-sparse comparisons. + +Class: sptensor +- Added new functions: not, and, or, xor, eq, ne, le, lt, ge, gt, isequal +- sptensor: Fixed bug where a 1D tensor was not correctly converted to + a sparse tensor. Also, added ability to accept an MDA as an input + and to accept a list of logical values as well as numerics. +- subsref: Fixed bug on subscripted reference to an empty tensor. +- ttt: Major overhaul that fixes a number of bugs and improves + efficiency dramatically. +- nvecs: Improved efficiency by converting to MATLAB sparse matrix + and calling eigs on that rather than calling eigs with the aatx + function. +- disp/display: Fixed bug that caused tensors with a *single* element + to display incorrectly. +- full: Fixed bug that caused it to fail if called on a completely + empty tensor. + +Class: ttensor +- innerprod/norm/nvecs: Improved efficiency. +- ttm: Removed errant debug print statements. + +Class: ktensor +- datadisp.m: Minor changes to formatting. + +Other +- License.txt: Removed an errant "7.3" that was in the text. +- Fixed top-level contents file and added version information so that + it will show up from MATLAB's ver command. + +========================================= +Changes from Version 1.0 (April 13, 2006) +========================================= + +Classes +- Added support for sparse tensors (sptensor and sptenmat) +- Renamed tensor_as_matrix to tenmat +- Renamed tucker_tensor to ttensor +- Renamed cp_tensor to ktensor +- Many functions have substantially improved efficiency + +Changes to the tensor class +- Removed functions: issamesize, order, shiftdim +- Renamed functions: multiarrayop to tenfun +- New functions: collapse, contract, find, full, innerprod, mttkrp, nvecs, + scale + +Changes to the ktensor class (formerly cp_tensor) +- Removed functions: issamesize, order +- New functions: datadisp, double, end, fixsigns, innerprod, mttkrp, + nvecs, times, ttm + +Changes to the ttensor class (formerly tucker_tensor) +- Removed functions: issamesize, order +- New functions: double, end, innerprod, mttkrp, norm, nvecs, ttm, ttv + +Changes to the tenmat class (formerly tensor_as_matrix) +- New functions: end, minus, norm, plus, uminus, uplus + +Changes to examples, algorithms, and documentation +- The examples directory no longer exists. +- Instead, documentation has been incorporated directly into the + MATLAB help navigator. +- Also, a new algorithms directory has been added with two ALS methods + for CANDECOMP/PARAFAC and Tucker. + +$Id: RELEASE_NOTES.txt,v 1.16 2010/03/22 16:08:13 tgkolda Exp $ diff --git a/external/tensor_toolbox_2.5/cp_als.m b/external/tensor_toolbox_2.5/cp_als.m new file mode 100755 index 0000000..48fe47d --- /dev/null +++ b/external/tensor_toolbox_2.5/cp_als.m @@ -0,0 +1,187 @@ +function [P,Uinit,output] = cp_als(X,R,varargin) +%CP_ALS Compute a CP decomposition of any type of tensor. +% +% P = CP_ALS(X,R) computes an estimate of the best rank-R +% CP model of a tensor X using an alternating least-squares +% algorithm. The input X can be a tensor, sptensor, ktensor, or +% ttensor. The result P is a ktensor. +% +% P = CP_ALS(X,R,'param',value,...) specifies optional parameters and +% values. Valid parameters and their default values are: +% 'tol' - Tolerance on difference in fit {1.0e-4} +% 'maxiters' - Maximum number of iterations {50} +% 'dimorder' - Order to loop through dimensions {1:ndims(A)} +% 'init' - Initial guess [{'random'}|'nvecs'|cell array] +% 'printitn' - Print fit every n iterations; 0 for no printing {1} +% +% [P,U0] = CP_ALS(...) also returns the initial guess. +% +% [P,U0,out] = CP_ALS(...) also returns additional output that contains +% the input parameters. +% +% Note: The "fit" is defined as 1 - norm(X-full(P))/norm(X) and is +% loosely the proportion of the data described by the CP model, i.e., a +% fit of 1 is perfect. +% +% Examples: +% X = sptenrand([5 4 3], 10); +% P = cp_als(X,2); +% P = cp_als(X,2,'dimorder',[3 2 1]); +% P = cp_als(X,2,'dimorder',[3 2 1],'init','nvecs'); +% U0 = {rand(5,2),rand(4,2),[]}; %<-- Initial guess for factors of P +% [P,U0,out] = cp_als(X,2,'dimorder',[3 2 1],'init',U0); +% P = cp_als(X,2,out.params); %<-- Same params as previous run +% +% See also KTENSOR, TENSOR, SPTENSOR, TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +%% Extract number of dimensions and norm of X. +N = ndims(X); +normX = norm(X); + +%% Set algorithm parameters from input or by using defaults +params = inputParser; +params.addParamValue('tol',1e-4,@isscalar); +params.addParamValue('maxiters',50,@(x) isscalar(x) & x > 0); +params.addParamValue('dimorder',1:N,@(x) isequal(sort(x),1:N)); +params.addParamValue('init', 'random', @(x) (iscell(x) || ismember(x,{'random','nvecs'}))); +params.addParamValue('printitn',1,@isscalar); +params.parse(varargin{:}); + +%% Copy from params object +fitchangetol = params.Results.tol; +maxiters = params.Results.maxiters; +dimorder = params.Results.dimorder; +init = params.Results.init; +printitn = params.Results.printitn; + +%% Error checking + +%% Set up and error checking on initial guess for U. +if iscell(init) + Uinit = init; + if numel(Uinit) ~= N + error('OPTS.init does not have %d cells',N); + end + for n = dimorder(2:end); + if ~isequal(size(Uinit{n}),[size(X,n) R]) + error('OPTS.init{%d} is the wrong size',n); + end + end +else + % Observe that we don't need to calculate an initial guess for the + % first index in dimorder because that will be solved for in the first + % inner iteration. + if strcmp(init,'random') + Uinit = cell(N,1); + for n = dimorder(2:end) + Uinit{n} = rand(size(X,n),R); + end + elseif strcmp(init,'nvecs') || strcmp(init,'eigs') + Uinit = cell(N,1); + for n = dimorder(2:end) + Uinit{n} = nvecs(X,n,R); + end + else + error('The selected initialization method is not supported'); + end +end + +%% Set up for iterations - initializing U and the fit. +U = Uinit; +fit = 0; + +if printitn>0 + fprintf('\nCP_ALS:\n'); +end + +%% Main Loop: Iterate until convergence + +if (isa(X,'sptensor') || isa(X,'tensor')) && (exist('cpals_core','file') == 3) + + %fprintf('Using C++ code\n'); + [lambda,U] = cpals_core(X, Uinit, fitchangetol, maxiters, dimorder); + P = ktensor(lambda,U); + +else + + for iter = 1:maxiters + + fitold = fit; + + % Iterate over all N modes of the tensor + for n = dimorder(1:end) + + % Calculate Unew = X_(n) * khatrirao(all U except n, 'r'). + Unew = mttkrp(X,U,n); + + % Compute the matrix of coefficients for linear system + Y = ones(R,R); + for i = [1:n-1,n+1:N] + Y = Y .* (U{i}'*U{i}); + end + + % Need to figure out which of the following lines works better. + % Meanwhile, we'll stick witht he line from TTB 2.2 since that is + % what seems to work best based on preliminary testing. + %Unew = Unew * pinv(Y); %<- Line from TTB 2.3. + Unew = (Y \ Unew')'; %<- Line from TTB 2.2. + + % Normalize each vector to prevent singularities in coefmatrix + if iter == 1 + lambda = sqrt(sum(Unew.^2,1))'; %2-norm + else + lambda = max( max(Unew,[],1), 1 )'; %max-norm + end + Unew = Unew * spdiags(1./lambda,0,R,R); + if issparse(Unew) + U{n} = full(Unew); % for the case R=1 + else + U{n} = Unew; + end + end + + P = ktensor(lambda,U); + normresidual = sqrt( normX^2 + norm(P)^2 - 2 * innerprod(X,P) ); + fit = 1 - (normresidual / normX); %fraction explained by model + fitchange = abs(fitold - fit); + + if mod(iter,printitn)==0 + fprintf(' Iter %2d: fit = %e fitdelta = %7.1e\n', iter, fit, fitchange); + end + + % Check for convergence + if (iter > 1) && (fitchange < fitchangetol) + break; + end + end +end + + +%% Clean up final result +% Arrange the final tensor so that the columns are normalized. +P = arrange(P); +% Fix the signs +P = fixsigns(P); + +if printitn>0 + normresidual = sqrt( normX^2 + norm(P)^2 - 2 * innerprod(X,P) ); + fit = 1 - (normresidual / normX); %fraction explained by model + fprintf(' Final fit = %e \n', fit); +end + +output = struct; +output.params = params.Results; +output.iters = iter; diff --git a/external/tensor_toolbox_2.5/cp_apr.m b/external/tensor_toolbox_2.5/cp_apr.m new file mode 100755 index 0000000..3f47167 --- /dev/null +++ b/external/tensor_toolbox_2.5/cp_apr.m @@ -0,0 +1,242 @@ +function [M,Minit,output] = cp_apr(X, R, varargin) +%CP_APR Compute nonnegative CP with alternating Poisson regression. +% +% M = CP_APR(X, R) computes an estimate of the best rank-R +% CP model of a tensor X using an alternating Poisson regression. +% The input X can be a tensor, sptensor, ktensor, or ttensor. The +% result P is a ktensor. +% +% M = CP_APR(X, R, 'param', value, ...) specifies optional parameters and +% values. Valid parameters and their default values are: +% 'tol' - Tolerance on the inner KKT violation {1.0e-4} +% 'maxiters' - Maximum number of iterations {1000} +% 'maxinneriters' = Maximum number of inner iterations {10} +% 'init' - Initial guess [{'random'}|ktensor] +% 'epsilon' - parameter to avoid divide by zero {100*eps} +% 'kappatol' - tolerance on complementary slackness {100*eps} +% 'kappa' - offset to fix complementary slackness {10*eps} +% 'printitn' - Print every n outer iterations; 0 for no printing {1} +% 'printinneritn' - Print every n inner iterations {0} +% +% [M,M0] = CP_APR(...) also returns the initial guess. +% +% [M,M0,out] = CP_APR(...) also returns additional output. +% out.kktViolations - maximum kkt violation per iteration +% out.nInnerIters - number of inner iterations per iteration +% out.nViolations - number of factor matrices needing complementary +% slackness adjustment per iteration +% out.nTotalIters - total number of inner iterations +% +% REFERENCE: E. C. Chi and T. G. Kolda. On Tensors, Sparsity, and +% Nonnegative Factorizations, arXiv:1112.2414 [math.NA], December 2011, +% URL: http://arxiv.org/abs/1112.2414. Submitted for publication. +% +% See also CP_ALS, KTENSOR, TENSOR, SPTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +%% Extract dimensions of X and number of dimensions of X. +N = ndims(X); + +%% Set algorithm parameters from input or by using defaults. +params = inputParser; +params.addParamValue('epsilon',1e-10,@isscalar); +params.addParamValue('tol',1e-4,@isscalar); +params.addParamValue('maxiters',1000,@(x) isscalar(x) & x > 0); +params.addParamValue('init','random',@(x) (isa(x,'ktensor') || ismember(x,{'random'}))); +params.addParamValue('printitn',1,@isscalar); +params.addParamValue('kappa',1e-2,@isscalar); +params.addParamValue('kappatol',1e-10,@isscalar); +params.addParamValue('maxinneriters',10,@isscalar); +params.addParamValue('printinneritn',0,@isscalar); +params.parse(varargin{:}); + + +%% Copy from params object. +epsilon = params.Results.epsilon; +tol = params.Results.tol; +maxOuterIters = params.Results.maxiters; +Minit = params.Results.init; +kappa = params.Results.kappa; +kappaTol = params.Results.kappatol; +maxInnerIters = params.Results.maxinneriters; +printOuterItn = params.Results.printitn; +printInnerItn = params.Results.printinneritn; +kktViolations = -ones(maxOuterIters,1); +nInnerIters = zeros(maxOuterIters,1); + +%% Set up and error checking on initial guess for U. +if isa(Minit,'ktensor') + if ndims(Minit) ~= N + error('Initial guess does not have the right number of dimensions'); + end + + if ncomponents(Minit) ~= R + error('Initial guess does not have the right number of components'); + end + + for n = 1:N + if size(Minit,n) ~= size(X,n) + error('Dimension %d of the initial guess is the wrong size',n); + end + end +elseif strcmp(Minit,'random') + F = cell(N,1); + for n = 1:N + F{n} = rand(size(X,n),R); + end + Minit = ktensor(F); +else + error('The selected initialization method is not supported'); +end + + +%% Set up for iterations - initializing M and Phi. +M = normalize(Minit,[],1); +Phi = cell(N,1); +kktModeViolations = zeros(N,1); + +if printOuterItn > 0 + fprintf('\nCP_APR:\n'); +end + +nViolations = zeros(maxOuterIters,1); + +%% Main Loop: Iterate until convergence. +for iter = 1:maxOuterIters + + isConverged = true; + for n = 1:N + + % Make adjustments to entries of M{n} that are violating + % complementary slackness conditions. + if (iter > 1) + V = (Phi{n} > 1) & (M{n} < kappaTol); + if any(V(:)) + nViolations(iter) = nViolations(iter) + 1; + M{n}(V>0) = M{n}(V>0) + kappa; + end + end + + % Shift the weight from lambda to mode n + M = redistribute(M,n); + + % Calculate product of all matrices but the n-th + % (In sparse case, only calcuates entries corresponding to nonzeros in X.) + Pi = calculatePi(X, M, R, n, N); + + % Do the multiplicative updates + for i = 1:maxInnerIters + + % Count the inner iterations + nInnerIters(iter) = nInnerIters(iter) + 1; + + % Calculate matrix for multiplicative update + Phi{n} = calculatePhi(X, M, R, n, Pi, epsilon); + + % Check for convergence + kktModeViolations(n) = max(abs(vec(min(M.U{n},1-Phi{n})))); + if (kktModeViolations(n) < tol) + break; + else + isConverged = false; + end + + % Do the multiplicative update + M{n} = M{n} .* Phi{n}; + + % Print status + if mod(i, printInnerItn)==0 + fprintf(' Mode = %1d, Inner Iter = %2d, KKT violation = %.6e\n', n, i, kktModeViolations(n)); + end + end + + % Shift weight from mode n back to lambda + M = normalize(M,[],1,n); + + end + + kktViolations(iter) = max(kktModeViolations); + + if (mod(iter,printOuterItn)==0) + fprintf(' Iter %4d: Inner Its = %2d KKT violation = %.6e, nViolations = %2d\n', ... + iter, nInnerIters(iter), kktViolations(iter), nViolations(iter)); + end + + % Check for convergence + if (isConverged) + break; + end +end + +%% Clean up final result +M = normalize(M,'sort',1); + +if printOuterItn>0 + normX = norm(X); + normresidual = sqrt( normX^2 + norm(M)^2 - 2 * innerprod(X,M) ); + fit = 1 - (normresidual / normX); %fraction explained by model + fprintf('===========================================\n'); + fprintf(' Final log-likelihood = %e \n', tt_loglikelihood(X,M)); + fprintf(' Final least squares fit = %e \n', fit); + fprintf(' Final KKT violation = %7.7e\n', kktViolations(iter)); + fprintf(' Total inner iterations = %d\n', sum(nInnerIters)); +end + +output = struct; +output.params = params.Results; +output.kktViolations = kktViolations(1:iter); +output.nInnerIters = nInnerIters(1:iter); +output.nViolations = nViolations(1:iter); +output.nTotalIters = sum(nInnerIters); + + +end + +function Pi = calculatePi(X, M, R, n, N) + +if (isa(X,'sptensor')) + Pi = ones(nnz(X), R); + for nn = [1:n-1,n+1:N] + Pi = M{nn}(X.subs(:,nn),:).*Pi; + end +else + U = M.U; + Pi = khatrirao(U{[1:n-1,n+1:N]},'r'); +end + +end + +function Phi = calculatePhi(X, M, R, n, Pi, epsilon) + +if (isa(X,'sptensor')) + Phi = -ones(size(X,n),R); + xsubs = X.subs(:,n); + v = sum(M.U{n}(xsubs,:).*Pi,2); + wvals = X.vals ./ max(v, epsilon); + for r = 1:R + Yr = accumarray(xsubs, wvals .* Pi(:,r), [size(X,n) 1]); + Phi(:,r) = Yr; + end +else + Xn = double(tenmat(X,n)); + V = M.U{n}*Pi'; + W = Xn ./ max(V, epsilon); + Y = W * Pi; + Phi = Y; +end + +end + +function y = vec(x) +y = x(:); +end diff --git a/external/tensor_toolbox_2.5/cp_nmu.m b/external/tensor_toolbox_2.5/cp_nmu.m new file mode 100755 index 0000000..c866c92 --- /dev/null +++ b/external/tensor_toolbox_2.5/cp_nmu.m @@ -0,0 +1,171 @@ +function [P,Uinit] = cp_nmu(X,R,opts) +%CP_NMU Compute nonnegative CP with multiplicative updates. +% +% P = CP_NMU(X,R) computes an estimate of the best rank-R PARAFAC +% model of a tensor X with nonnegative constraints on the factors. +% This version uses the Lee & Seung multiplicative updates from +% their NMF algorithm. The input X can be a tensor, sptensor, +% ktensor, or ttensor. The result P is a ktensor. +% +% P = CP_NMU(X,R,OPTS) specify options: +% OPTS.tol: Tolerance on difference in fit {1.0e-4} +% OPTS.maxiters: Maximum number of iterations {50} +% OPTS.dimorder: Order to loop through dimensions {1:ndims(A)} +% OPTS.init: Initial guess [{'random'}|'nvecs'|cell array] +% OPTS.printitn: Print fit every n iterations {1} +% +% [P,U0] = CP_NMU(...) also returns the initial guess. +% +% Examples: +% X = sptenrand([5 4 3], 10); +% P = cp_nmu(X,2); +% P = cp_nmu(X,2,struct('dimorder',[3 2 1])); +% P = cp_nmu(X,2,struct('dimorder',[3 2 1],'init','nvecs')); +% U0 = {rand(5,2),rand(4,2),[]}; %<-- Initial guess for factors of P +% P = cp_nmu(X,2,struct('dimorder',[3 2 1],'init',{U0})); +% +% See also KTENSOR, TENSOR, SPTENSOR, TTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Fill in optional variable +if ~exist('opts','var') + opts = struct; +end + +%% Extract number of dimensions and norm of X. +N = ndims(X); +normX = norm(X); + +%% Set algorithm parameters from input or by using defaults +fitchangetol = setparam(opts,'tol',1e-4); +maxiters = setparam(opts,'maxiters',500); +dimorder = setparam(opts,'dimorder',1:N); +init = setparam(opts,'init','random'); +printitn = setparam(opts,'printitn',1); +epsilon = 1e-12; % Small number to protect against round-off error + +%% Error checking +% Error checking on maxiters +if maxiters < 0 + error('OPTS.maxiters must be positive'); +end + +% Error checking on dimorder +if ~isequal(1:N,sort(dimorder)) + error('OPTS.dimorder must include all elements from 1 to ndims(X)'); +end + +%% Set up and error checking on initial guess for U. +if iscell(init) + Uinit = init; + if numel(Uinit) ~= N + error('OPTS.init does not have %d cells',N); + end + for n = dimorder(1:end); + if ~isequal(size(Uinit{n}),[size(X,n) R]) + error('OPTS.init{%d} is the wrong size',n); + end + end +else + if strcmp(init,'random') + Uinit = cell(N,1); + for n = dimorder(1:end) + Uinit{n} = rand(size(X,n),R) + 0.1; + end + elseif strcmp(init,'nvecs') || strcmp(init,'eigs') + Uinit = cell(N,1); + for n = dimorder(1:end) + k = min(R,size(X,n)-2); + fprintf(' Computing %d leading e-vectors for factor %d.\n',k,n); + Uinit{n} = abs(nvecs(X,n,k)); + if (k < R) + Uinit{n} = [Uinit{n} rand(size(X,n),R-k)]; + end + end + else + error('The selected initialization method is not supported'); + end +end + +%% Set up for iterations - initializing U and the fit. +U = Uinit; +fit = 0; + +if printitn>0 + fprintf('\nNonnegative PARAFAC:\n'); +end + +%% Main Loop: Iterate until convergence +for iter = 1:maxiters + + fitold = fit; + + % Iterate over all N modes of the tensor + for n = dimorder(1:end) + + % Compute the matrix of coefficients for linear system + Y = ones(R,R); + for i = [1:n-1,n+1:N] + Y = Y .* (U{i}'*U{i}); + end + Y = U{n} * Y; + + % Initialize matrix of unknowns + Unew = U{n}; + + % Calculate Unew = X_(n) * khatrirao(all U except n, 'r'). + tmp = mttkrp(X,U,n) + epsilon; + + % Update unknowns + Unew = Unew .* tmp; + Unew = Unew ./ (Y + epsilon); + + U{n} = Unew; + end + + P = ktensor(U); + normresidual = sqrt( normX^2 + norm(P)^2 - 2 * innerprod(X,P) ); + fit = 1 - (normresidual / normX); %fraction explained by model + fitchange = abs(fitold - fit); + + if mod(iter,printitn)==0 + fprintf(' Iter %2d: fit = %e fitdelta = %7.1e\n', iter, fit, fitchange); + end + + % Check for convergence + if (iter > 1) && (fitchange < fitchangetol) + break; + end + +end + +%% Clean up final result +% Arrange the final tensor so that the columns are normalized. +P = arrange(P); + +if printitn>0 + normresidual = sqrt( normX^2 + norm(P)^2 - 2 * innerprod(X,P) ); + fit = 1 - (normresidual / normX); %fraction explained by model + fprintf(' Final fit = %e \n', fit); +end + +return; + +%% +function x = setparam(opts,name,default) +if isfield(opts,name); + x = opts.(name); +else + x = default; +end diff --git a/external/tensor_toolbox_2.5/cp_opt.m b/external/tensor_toolbox_2.5/cp_opt.m new file mode 100755 index 0000000..e83babb --- /dev/null +++ b/external/tensor_toolbox_2.5/cp_opt.m @@ -0,0 +1,137 @@ +function [P, P0, output] = cp_opt(Z,R,varargin) +%CP_OPT Fits a CP model to a tensor via optimization. +% +% K = CP_OPT(X,R) fits an R-component CANDECOMP/PARAFAC (CP) model +% to the tensor X. The result K is a ktensor. The function being +% optimized is F(K) = 1/2 || X - K ||^2. +% +% K = CP_OPT(X,R,'param',value,...) specifies additional +% parameters for the method. Specifically... +% +% 'alg' - Specfies optimization algorithm (default: 'ncg') +% 'ncg' Nonlinear Conjugate Gradient Method +% 'lbfgs' Limited-Memory BFGS Method +% 'tn' Truncated Newton +% +% 'init' - Initialization for factor matrices. (default: +% 'random'). This can be a cell array with the initial matrices or +% one of the following strings: +% 'random' Randomly generated via randn function +% 'nvecs' Selected as leading left singular vectors of X(n) +% +% 'alg_options' - Parameter settings for selected optimization +% algorithm. For example, type OPTIONS = NCG('defaults') to get +% the NCG algorithm options which can then me modified as passed +% through this function to NCG. +% +% [K, U0] = CP_OPT(...) also returns the initial guess. +% +% [K, U0, OUT] = CP_OPT(...) also returns a structure with the +% optimization exit flag, the final relative fit, and the full +% output from the optimization method. The fit is defined as +% +% FIT = 100 * (1 - ( F(K) / F(0) )). +% +% REFERENCE: E. Acar, D. M. Dunlavy and T. G. Kolda, A Scalable +% Optimization Approach for Fitting Canonical Tensor Decompositions, +% J. Chemometrics 25(2):67-86, February 2011 (doi:10.1002/cem.1335) +% +% For example usage, see the documentation for the tensor_toolbox +% and click on "All-at-once optimization for CP tensor decomposition". +% +% See also TENSOR, SPTENSOR, KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Check for POBLANO +if ~exist('poblano_params','file') + error(['CP_OPT requires Poblano Toolbox for Matlab. This can be ' ... + 'downloaded at http://software.sandia.gov/trac/poblano.']); +end + +%% Error checking +if ~isa(Z,'tensor') && ~isa(Z,'sptensor') + error('Z must be a tensor or a sptensor'); +end + +if (nargin < 2) + error('Error: invalid input arguments'); +end + +%% Set parameters +params = inputParser; +params.addParamValue('alg', 'ncg', @(x) ismember(x,{'ncg','tn','lbfgs'})); +params.addParamValue('init', 'random', @(x) (iscell(x) || ismember(x,{'random','nvecs'}))); +params.addOptional('alg_options', '', @isstruct); +params.parse(varargin{:}); + +%% Set up optimization algorithm +switch (params.Results.alg) + case 'ncg' + fhandle = @ncg; + case 'tn' + fhandle = @tn; + case 'lbfgs' + fhandle = @lbfgs; +end + +%% Set up optimization algorithm options +if isempty(params.Results.alg_options) + options = feval(fhandle, 'defaults'); +else + options = params.Results.alg_options; +end + + +%% Initialization +sz = size(Z); +N = length(sz); + +if iscell(params.Results.init) + P0 = params.Results.init; +elseif strcmpi(params.Results.init,'random') + P0 = cell(N,1); + for n=1:N + P0{n} = randn(sz(n),R); + for j=1:R + P0{n}(:,j) = P0{n}(:,j) / norm(P0{n}(:,j)); + end + end +elseif strcmpi(params.Results.init,'nvecs') + P0 = cell(N,1); + for n=1:N + P0{n} = nvecs(Z,n,R); + end +else + error('Initialization type not supported') +end + +%% Fit CP using CPOPT +normsqr = norm(Z)^2; +out = feval(fhandle, @(x)tt_cp_fun(x,Z,normsqr), tt_fac_to_vec(P0), options); + +% compute factors and model fit +P = ktensor(tt_cp_vec_to_fac(out.X, Z)); +if nargout > 2 + output.ExitFlag = out.ExitFlag; + output.Fit = 100 * (1 - out.F /(0.5 * normsqr)); + output.OptOut = out; +end + +%% Clean up final result +% Arrange the final tensor so that the columns are normalized. +P = arrange(P); +% Fix the signs +P = fixsigns(P); + + diff --git a/external/tensor_toolbox_2.5/cp_wopt.m b/external/tensor_toolbox_2.5/cp_wopt.m new file mode 100755 index 0000000..a78c6d2 --- /dev/null +++ b/external/tensor_toolbox_2.5/cp_wopt.m @@ -0,0 +1,148 @@ +function [P, P0, output] = cp_wopt(Z,W,R,varargin) +%CP_WOPT Fits a weighted CP model to a tensor via optimization. +% +% K = CP_WOPT(X,W,R) fits an R-component weighted CANDECOMP/PARAFAC +% (CP) model to the tensor X, where W is an indicator for missing +% data (0 = missing, 1 = present). The result K is a ktensor. It is +% assumed that missing entries of X have been sent to zero (but not +% that all zeros correspond to missing entries.) The function being +% optimized is F(K) = 1/2 || W .* (X - K) ||^2. +% +% K = CP_WOPT(X,W,R,'param', value,...) specifies additional +% parameters for the method. Specifically... +% +% 'alg' - Specfies optimization algorithm (default: 'ncg') +% 'ncg' Nonlinear Conjugate Gradient Method +% 'lbfgs' Limited-Memory BFGS Method +% 'tn' Truncated Newton +% +% 'init' - Initialization for factor matrices. (default: +% 'random'). This can be a cell array with the initial matrices or +% one of the following strings: +% 'random' Randomly generated via randn function +% 'nvecs' Selected as leading left singular vectors of X(n) +% +% 'alg_options' - Parameter settings for selected optimization +% algorithm. For example, type OPTIONS = NCG('defaults') to get +% the NCG algorithm options which can then me modified as passed +% through this function to NCG. +% +% 'fun' - Specifies the type of implementation (default: 'auto') +% 'auto' Dense implementation +% 'sparse' Sparse implementation +% 'sparse_lowmem' Memory efficient sparse implementation +% +% [K, U0] = CP_WOPT(...) also returns the initial guess. +% +% [K, U0, OUT] = CP_WOPT(...) also returns a structure with the +% optimization exit flag, the final relative fit, and the full +% output from the optimization method. +% +% REFERENCE: E. Acar, D. M. Dunlavy, T. G. Kolda and M. Mørup, Scalable +% Tensor Factorizations for Incomplete Data, Chemometrics and Intelligent +% Laboratory Systems 106(1):41-56, March 2011 +% (doi:10.1016/j.chemolab.2010.08.004) +% +% See also CP_OPT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Check for POBLANO +if ~exist('poblano_params','file') + error(['CP_WOPT requires Poblano Toolbox for Matlab. This can be ' ... + 'downloaded at http://software.sandia.gov/trac/poblano.']); +end + +%% Set parameters +params = inputParser; +params.addParamValue('alg','ncg', @(x) ismember(x,{'ncg','tn','lbfgs'})); +params.addParamValue('init','random', @(x) (iscell(x) || ismember(x,{'random','nvecs'}))); +params.addParamValue('fun','auto', @(x) ismember(x,{'auto','default','sparse','sparse_lowmem'})); +params.addParamValue('alg_options', '', @isstruct); +params.parse(varargin{:}); + +%% Set up optimization algorithm +switch (params.Results.alg) + case 'ncg' + opthandle = @ncg; + case 'tn' + opthandle = @tn; + case 'lbfgs' + opthandle = @lbfgs; +end + +%% Set up optimization algorithm options +if isempty(params.Results.alg_options) + options = feval(opthandle, 'defaults'); +else + options = params.Results.alg_options; +end + +%% Set up function handle +normZsqr = norm(Z)^2; +funtype = params.Results.fun; + +if (isequal(funtype,'auto') && isa(Z,'tensor')) || isequal(funtype,'default') + funhandle = @(x) tt_cp_wfun(Z,W,x,normZsqr); +else + if ~isa(Z,'sptensor') || ~isa(W,'sptensor') + warning('Converting dense tensor to sparse'); + Z = sptensor(Z); + W = sptensor(W); + end + Zvals = tt_cp_wfg_sparse_setup(Z,W); + fflag = ~isequal(funtype,'sparse_lowmem'); + funhandle = @(x) tt_cp_wfun(Zvals,W,x,normZsqr,fflag); +end + +%% Initial guess +sz = size(Z); +N = length(sz); + +if iscell(params.Results.init) + P0 = params.Results.init; +elseif strcmpi(params.Results.init,'random') + P0 = cell(N,1); + for n=1:N + P0{n} = randn(sz(n),R); + for j=1:R + P0{n}(:,j) = P0{n}(:,j) / norm(P0{n}(:,j)); + end + end +elseif strcmpi(params.Results.init,'nvecs') + P0 = cell(N,1); + for n=1:N + P0{n} = nvecs(Z,n,R); + end +else + error('Initialization type not supported') +end + +%% Fit CP using CP_WOPT by ignoring missing entries +out = feval(opthandle, funhandle, tt_fac_to_vec(P0), options); + +P = ktensor(tt_cp_vec_to_fac(out.X,Z)); +if nargout > 1 + output.ExitFlag = out.ExitFlag; + output.FuncEvals = out.FuncEvals; + output.f = out.F; + output.G = tt_cp_vec_to_fac(out.G,W); + output.OptOut = out; +end + + +%% Clean up final result +% Arrange the final tensor so that the columns are normalized. +P = arrange(P); +% Fix the signs +P = fixsigns(P); diff --git a/external/tensor_toolbox_2.5/create_guess.m b/external/tensor_toolbox_2.5/create_guess.m new file mode 100755 index 0000000..4aa0e7e --- /dev/null +++ b/external/tensor_toolbox_2.5/create_guess.m @@ -0,0 +1,155 @@ +function U = create_guess(varargin) +%CREATE_GUESS Creates initial guess for CP or Tucker fitting. +% +% U = CREATE_GUESS('Param',value,...) creates an initial guess at the +% factor matrices for a CP or Tucker decomposition. The factors can be +% generated randomly, random orthogonal, etc. If the tensor is provided, +% it can be alternatively generated via the HO-SVD. +% +% --- Parameters --- +% +% 'Factor_Generator' - Method to be used to generate the factor matrices. +% Options: +% - 'rand' (uniform on [0,1]) +% - 'randn' (standard normal distribution) +% - 'orthogonal' +% - 'stochastic' (uniform on [0,1] with column sums rescaled to 1) +% - 'nvecs' (HOSVD solution) +% - 'pertubation' of the true solution +% Alternatively, pass in a function that accepts two arguments (the size +% of the matrix) and generates the desired factor. Default: 'rand' +% +% 'Size' - Size of the tensor. Required to be specified unless 'Data' or +% 'Soln' is given. Default: [] +% +% 'Num_Factors' - Number of factors (can be either a single value for CP +% or a vector for Tucker). Required to be specified unless 'Soln' is +% given. Default: [] +% +% 'Data' - The actual tensor to be fit. Required if 'nvecs' is the +% selected Factor Generator. The 'Size' parameter is ignored if this +% is specified. Default: [] +% +% 'Soln' - The actual solution to the problem. Required if 'pertubation' +% is the selected Factor Generator. The 'Size' and 'Num_Factors' +% parameters are ignored if this is specified. Default: [] +% +% 'Pertubation' - Size of the pertubation is the 'pertubation' option is +% selected under 'Factor_Generator'. The pertubation is of the form U+p*N +% where U is the original factor matrix, N is a noise matrix with entries +% selected for a standard normal distribution, and p is the pertubation +% parameter times ||U||/||N||. Default: 0.10 +% +% 'Skip' - Specifies mode to skip in initial guess generation (this is +% useful for ALS). Default: 0 (no skipping) +% +% 'State' - State of the random number generator. This can be used +% to reproduce results. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Random set-up +defaultStream = RandStream.getDefaultStream; + +%% Parse inputs +p = inputParser; +p.addParamValue('Factor_Generator', 'rand', @(x) isa(x,'function_handle') || ... + ismember(lower(x),{'rand','randn','orthogonal','stochastic','nvecs','pertubation'})); +p.addParamValue('Size', [], @(x) isempty(x) || all(x)); +p.addParamValue('Num_Factors', [], @(x) isempty(x) || all(x)); +p.addParamValue('Soln', [], @(x) isempty(x) || isa(x,'ktensor') || isa(x,'ttensor')); +p.addParamValue('Data', [], @(x) isempty(x) || isa(x,'tensor') || isa(x,'sptensor')); +p.addParamValue('Pertubation', 0.10, @(x) x >= 0 & x < 1); +p.addParamValue('Skip', 0); +p.addParamValue('State', defaultStream.State, @(x) true); +p.parse(varargin{:}); +params = p.Results; + +%% Initialize random number generator with specified state. +defaultStream.State = params.State; + +%% Determine problem size +if ~isempty(params.Soln) + sz = size(params.Soln); +elseif ~isempty(params.Data) + sz = size(params.Data); +else + sz = params.Size; +end +if isempty(sz) + error('Size must be specified'); +end +nd = length(sz); +modes = setdiff(1:nd,params.Skip); + +%% Determine number of factors +if ~isempty(params.Soln) + nf = zeros(nd,1); + for n = 1:nd + nf(n) = size(params.Soln.U{n},2); + end +else + nf = params.Num_Factors; + if length(nf) == 1 + nf = nf * ones(nd,1); + end +end + +%% Create factor matrices +U = cell(nd,1); +if isa(params.Factor_Generator,'function_handle') + for n = modes + U{n} = params.Factor_Generator(sz(n), nf(n)); + end + return; +end + +switch(params.Factor_Generator) + case 'rand' + for n = modes + U{n} = rand(sz(n), nf(n)); + end + case 'randn' + for n = modes + U{n} = randn(sz(n), nf(n)); + end + case 'orthogonal' + for n = modes + X = tt_RandOrthMat(sz(n)); + U{n} = X(:,1:nf(n)); + end + case 'stochastic' + for n = modes + X = rand(sz(n), nf(n)); + S = sum(X,1); + U{n} = X * diag(1./S); + end + case 'nvecs' + if isempty(params.Data) + error('Data required for nvecs initialization'); + end + for n = modes + U{n} = nvecs(params.Data,n,nf(n)); + end + case 'pertubation' + if isempty(params.Soln) + error('Soln required for pertubation initialization'); + end + for n = modes + X = params.Soln{n}; + N = rand(size(X)); + p = params.Pertubation * norm(X,'fro') / norm(N,'fro'); + U{n} = X + p * N; + end +end + \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/create_problem.m b/external/tensor_toolbox_2.5/create_problem.m new file mode 100755 index 0000000..99ab4b2 --- /dev/null +++ b/external/tensor_toolbox_2.5/create_problem.m @@ -0,0 +1,376 @@ +function [info,params] = create_problem(varargin) +%CREATE_PROBLEM Create test problems for tensor factorizations. +% +% INFO = CREATE_PROBLEM('Param',value,...) creates a tensor factorization +% test problem. It generates a solution corresponding to a ktensor or a +% ttensor, and then it generates an example data tensor which has that +% underlying factorization. The data tensor can be optionally corrupted +% with noise, generated via a special procedure to produce a sparse +% tensor, or even have missing data. +% +% [INFO,PARAMS] = CREATE_PROBLEM(...) also returns the parameters that +% were used to generate the problem. An indentical problem can be +% generated via INFO_COPY = CREATE_PROBLEM(PARAMS). +% +% --- General --- +% +% 'State' - State of the random number generator. This can be used +% to reproduce results. +% +% --- Solution Parameters --- +% +% The desired solution will be returned in the "Soln" field of INFO. It +% will be either a ktensor or ttensor, depending on the user option +% 'Type', described below. +% +% 'Soln' - A CP or Tucker tensor that is the desired solution. Renders +% all other solution parameters obsolete. Default: [] +% +% 'Type' - CP or Tucker. Default: 'CP' +% +% 'Size' - Size of the tensor. Default: [100 100 100] +% +% 'Num_Factors' - Number of factors. Default: 2 (or [2 2 2] for Tucker) +% +% 'Symmetric' - List of modes that should be symmetric, i.e., have +% identical factor matrices. This cell array of lists of modes if +% different subsets should be symmetric, i.e., {[1 2],[3 4]} says that +% modes 1 and 2 and 3 and 4 are symmetric. +% +% 'Factor_Generator' - Method to be used to generate the factor matrices. +% Options are 'rand' (uniform on [0,1]), 'randn' (standard normal +% distribution), 'orthogonal', or 'stochastic' (uniform on [0,1] +% with column sums rescaled to 1). Alternatively, pass in a function that +% accepts two arguments (the size of the matrix) and generates the +% desired factor. Default: 'randn' +% +% 'Lambda_Generator' - Method used to genate the lambda vector for CP +% solutions. The choices are the same as for the 'Factor_Generator'. +% Default: 'rand' +% +% 'Core_Generator' - Method used to generate the core tensor for Tucker +% solutions. The choices are 'rand' and 'randn' (as described above). +% Alternatively, pass in a function that accepts a vector-valued size and +% generates a tensor of the specified size. Default: 'randn' +% +% --- Missing Data Parameters --- +% +% The missing data pattern will be return in the "Pattern" data +% field of INFO. If there is no missing data, then this will just be an +% empty array. Otherwise, it will be a tensor that is zero whereever data +% is missing and one elsewhere. +% +% 'M' - The proportion of missing data *or* a tensor or sptensor that +% contains the missing data pattern as described above. Default: 0 +% +% 'Sparse_M' - Generate sparse rather than dense missing data pattern +% tensor. Only useful for large tensors that don't easily fit in memory +% and when M > 80%. Default: false. +% +% --- Data Parameters --- +% +% The data to be factorized will be returned in the "Data" field of INFO. +% It will have zeros for any entries that are missing (though not all +% zeros necessarily correspond to missing data). +% +% 'Sparse_Generation' - Generate a sparse tensor via a special procedure +% that works only for ktensor's (CP) that can be scaled so that the +% column factors and lambda are stochastic. Note that this geneartion +% procedure will modify lambda vector in the solution so that it is +% appropriately scaled for the number of inserted nonzeros. A value of +% zero means no sparse generation, and any positive value is the number +% of nonzeros to be inserted. Any value in the range (0,1) will be +% interpreted as a percentage. The procedure is incompatible with missing +% data. Default: 0 (no sparse geneartion). +% +% 'Noise' - Amount of Gaussian noise to add. Let N be a "noise" +% tensor with entries drawn from the standard norm distribution, and +% let Y be the noise-free tensor, i.e. Y = full(K). Then Z = Y + eta +% * norm(Y,'fro') / norm(N,'fro') * N is the noisy version of the +% tensor where eta is the percentage of noise to add. If the data tensor +% is sparse (either due to sparse generation or sparsity due to missing +% data), then noise is only generated at the nonzero entries. +% Default: 0.10 +% +% Examples: +% % Create a 100 x 100 x 100 problem with 5 factors (each entry from the +% % standard normal distribution) and 10% noise with diagonal lambda +% % values of all ones. +% info = createcreate_problem('Lambda_Generator', @ones); +% +% % Same as above except that the we use a special function to generate +% % factor matrices with a constant congruence of 0.9. +% info = create_problem('Factor_Generator', @(m,n) tt_ccong(m,n,.9), ... +% 'Lambda_Generator', @ones); +% +% See also CREATE_GUESS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +%% Random set-up +defaultStream = RandStream.getDefaultStream; + +%% Parse inputs +p = inputParser; +p.addParamValue('State', defaultStream.State, @(x) true); +p.addParamValue('Soln', [], @(x) isempty(x) || isa(x,'ktensor') || isa(x,'ttensor')); +p.addParamValue('Type', 'CP', @(x) ismember(lower(x),{'cp','tucker'})); +p.addParamValue('Size', [10 10 10], @all); +p.addParamValue('Num_Factors', 2, @all); +p.addParamValue('Factor_Generator', 'randn', @is_valid_matrix_generator); +p.addParamValue('Lambda_Generator', 'rand', @is_valid_matrix_generator); +p.addParamValue('Core_Generator', 'randn', @is_valid_tensor_generator); +p.addParamValue('M', 0, @(x) is_missing_data(x) || (x == 0)); +p.addParamValue('Sparse_M', false, @islogical); +p.addParamValue('Sparse_Generation', 0, @(x) x >= 0); +p.addParamValue('Symmetric', []); +p.addParamValue('Noise', 0.10, @(x) x >= 0 & x < 1); +% p.addParamValue('Rtest', 0, @(x) isscalar(x) & x >= 0); +% p.addParamValue('Init_Type', 'random', @(x) ismember(x,{'random','nvecs'})); +p.parse(varargin{:}); +params = p.Results; + +%% Initialize random number generator with specified state. +defaultStream.State = params.State; + +%% Error checking +if is_missing_data(params.M) && (params.Sparse_Generation > 0) + error('Cannot combine missing data and sparse generation'); +end + +if strcmpi(params.Type, 'tucker') && (params.Sparse_Generation > 0) + error('Sparse generation only supported for CP'); +end + +%% Check for incompatible parameters +if ~isempty(params.Symmetric) + if is_missing_data(params.M) + error('Not set up to generate a symmetric problem with missing data'); + end + if (params.Sparse_Generation ~= 0) + error('Not set up to generate a sparse symmetric problem'); + end +end + +%% Create return data structure +info = struct; +info.Soln = generate_solution(params); + +if is_missing_data(params.M) + info.Pattern = generate_missing_pattern(size(info.Soln), params); + info.Data = generate_data(info.Soln, info.Pattern, params); +elseif (params.Sparse_Generation) + [info.Data, info.Soln] = generate_data_sparse(info.Soln, params); +else + info.Data = generate_data(info.Soln, [], params); +end + +function D = generate_data(S, W, params) +%GENERATE_DATA Generate CP or Tucker data from a given solution. + +sz = size(S); +if isempty(W) + Rdm = tensor(randn([sz 1 1]), sz); + Z = full(S); + % Use symmetric noise for a symmetric problem + if ~isempty(params.Symmetric) + Rdm = symmetrize(Rdm, params.Symmetric); + end +else + if isa(W,'sptensor') + Rdm = sptensor(W.subs,randn(nnz(W),1),W.size); + Z = W.*S; + else + Rdm = W.*tensor(randn([sz 1 1]), sz); + Z = W.*full(S); + end +end + +D = Z + params.Noise * norm(Z) * Rdm / norm(Rdm); + +% Make sure the final result is *absolutely* symmetric +if ~isempty(params.Symmetric) + D = symmetrize(D, params.Symmetric); +end + +function output = prosample(nsamples, prob) +%PROSAMPLE Proportional sampling + +% Create bins +bins = min([0 cumsum(prob')],1); +bins(end) = 1; + +% Create indices +[~, output] = histc(rand(nsamples,1),bins); + + +function [Z,S] = generate_data_sparse(S,params) +%GENERATE_DATA_SPARSE Generate sparse CP data from a given solution. + +% Error check on S +if any(S.lambda < 0) + error('All lambda values must be nonnegative'); +end +if any(cellfun(@(x) any(x(:)<0), S.U)) + error('All factor matrices must be nonnegative'); +end +if ~strcmpi(params.Type,'CP') + error('Only works for CP'); +end +if ~isempty(params.Symmetric) + warning('Symmetry constraints have been ignored'); +end + +% Convert S to a probability tensor +P = normalize(S,[],1); +eta = sum(P.lambda); +P.lambda = P.lambda / eta; + +% Determine how many samples per component +nedges = params.Sparse_Generation; +nd = ndims(P); +nc = size(P.U{1},2); +csample = prosample(nedges, P.lambda); +csums = accumarray(csample,1,[nc 1]); + +% Determine subscripts for each randomly sampled entry +sz = size(S); +subs = cell(nc,1); +for c = 1:nc + nsample = csums(c); + if nsample == 0 + continue; + end + subs{c} = zeros(nsample,nd); + for d = 1:nd + PU = P.U{d}; + subs{c}(:,d) = prosample(nsample, PU(:,c)); + end +end + +% Assemble final tensor. Note that duplicates are summed. +allsubs = cell2mat(subs); +Z = sptensor(allsubs,1,sz); + +% Rescale S so that it is proportional to the number of edges inserted +S = P; +S.lambda = nedges * S.lambda; + +function W = generate_missing_pattern(sz, params) +%GENERATE_MISSING_PATTERN Generate a tensor pattern of missing data. + +M = params.M; +S = params.Sparse_M; +if isa(M, 'tensor') || isa(M, 'sptensor') + W = M; + return; +end +if M == 0 + W = []; + return; +end +if (M < 0.8) && S + warning('Setting sparse to false because there are less than 80% missing elements'); + S = false; +end +W = tt_create_missing_data_pattern(sz, M, S); + +function S = generate_solution(params) +%GENERATE_SOLUTION Generate factor matrices and other data for CP or Tucker + +if ~isempty(params.Soln) + S = params.Soln; + return; +end + +% Get size of final tensor +sz = params.Size; +nd = length(sz); + +% Get size of factors +nfactors = params.Num_Factors; +if numel(nfactors) == 1 + nfactors = nfactors * ones(size(sz)); +end +if any(size(nfactors) ~= size(sz)) + error('''Num_Factors'' should either be a single value or the same dimensions as ''Size''.'); +end + +% Create factor matrices +fgfh = get_generator(params.Factor_Generator); +U = cell(nd,1); +for n = 1:nd + U{n} = fgfh(sz(n), nfactors(n)); +end + +if ~isempty(params.Symmetric) + if ~iscell(params.Symmetric) + params.Symmetric = {params.Symmetric}; + end + for i = 1:length(params.Symmetric) + grp = params.Symmetric{i}; + for j = 2:length(grp) + U{grp(j)} = U{grp(1)}; + end + end +end + +% Create final ktensor or ttensor +switch lower(params.Type) + case {'cp'} + lgfh = get_generator(params.Lambda_Generator); + lambda = lgfh(nfactors(1),1); + S = ktensor(lambda,U); + case {'tucker'} + cgfh = get_generator(params.Core_Generator); + core = tensor(cgfh(nfactors)); + S = ttensor(core,U); + otherwise + error('Invalid choice for ''Type'''); +end + +function b = is_valid_matrix_generator(x) +b = isa(x,'function_handle') || ... + ismember(lower(x),{'rand','randn','orthogonal','stochastic'}); + +function b = is_valid_tensor_generator(x) +b = isa(x,'function_handle') || ismember(lower(x),{'rand','randn'}); + +function fh = get_generator(x) +if isa(x,'function_handle') + fh = x; + return; +end +switch lower(x) + case {'randn'} + fh = @randn; + case {'rand'} + fh = @rand; + case {'orthogonal'} + fh = @rand_orth_mat; + case {'stochastic'} + fh = @rand_column_stochastic; + otherwise + error('Invalid choice for generator'); +end + +function Y = rand_column_stochastic(M,N) +X = rand(M,N); +S = sum(X,1); +Y = X * diag(1./S); + +function Y = rand_orth_mat(M,N) +X = tt_RandOrthMat(M); +Y = X(:,1:N); + +function tf = is_missing_data(x) +tf = isa(x,'tensor') || isa(x,'sptensor') || (isscalar(x) && (x > 0)); diff --git a/external/tensor_toolbox_2.5/doc/A1_tensor_doc.m b/external/tensor_toolbox_2.5/doc/A1_tensor_doc.m new file mode 100755 index 0000000..e0ba453 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/A1_tensor_doc.m @@ -0,0 +1,194 @@ +%% Tensors +% Tensors are extensions of multidimensional arrays with additional +% operations defined on them. Here we explain the basics of creating and +% working with tensors. +%% Creating a tensor from an array +% The |tensor| command converts a (multidimensional) array to a tensor +% object. +M = ones(4,3,2); %<-- A 4 x 3 x 2 array. +X = tensor(M) %<-- Convert to a tensor object. +%% +% Optionally, you can specify a different shape for the tensor, so long as +% the input array has the right number of elements. +X = tensor(M,[2 3 4]) %<-- M has 24 elements. +%% Creating a one-dimensional tensor +% The tensor class explicitly supports order-one tensors as well as +% trailing singleton dimensions, but the size must be explicit in the +% constructor. By default, a column array produces a 2-way tensor. +X = tensor(rand(5,1)) %<-- Creates a 2-way tensor. +%% +% This is fixed by specifying the size explicitly. +X = tensor(rand(5,1),5) %<-- Creates a 1-way tensor. +%% Specifying trailing singleton dimensions in a tensor +% Likewise, trailing singleton dimensions must be explictly specified. +Y = tensor(rand(4,3,1)) %<-- Creates a 2-way tensor. +%% +Y = tensor(rand(4,3,1),[4 3 1]) %<-- Creates a 3-way tensor. +%% +% Unfortunately, the |whos| command does not report the size of 1D +% objects correctly (last checked for MATLAB 2006a). +whos X Y %<-- Doesn't report the right size for X! +%% The constituent parts of a tensor +X = tenrand([4 3 2]); %<-- Create data. +X.data %<-- The array. +%% +X.size %<-- The size. +%% Creating a tensor from its constituent parts +Y = tensor(X.data,X.size) %<-- Copies X. +%% Creating an empty tensor +% An empty constructor exists, primarily to support loading previously +% saved data in MAT-files. +X = tensor %<-- Creates an empty tensor. +%% Use tenone to create a tensor of all ones +X = tenones([3 4 2]) %<-- Creates a 3 x 4 x 2 tensor of ones. +%% Use tenzeros to create a tensor of all zeros +X = tenzeros([1 4 2]) %<-- Creates a 1 x 4 x 2 tensor of zeros. +%% Use tenrand to create a random tensor +X = tenrand([5 4 2]) %<-- Creates a random 5 x 4 x 2 tensor. +%% Use squeeze to remove singleton dimensions from a tensor +squeeze(Y) %<-- Removes singleton dimensions. +%% Use double to convert a tensor to a (multidimensional) array +double(Y) %<-- Converts Y to a standard MATLAB array. +%% +Y.data %<-- Same thing. +%% Use ndims and size to get the size of a tensor +ndims(Y) %<-- Number of dimensions (or ways). +%% +size(Y) %<-- Row vector with the sizes of all dimension. +%% +size(Y,3) %<-- Size of a single dimension. +%% Subscripted reference for a tensor +X = tenrand([3 4 2 1]); %<-- Create a 3 x 4 x 2 x 1 random tensor. +X(1,1,1,1) %<-- Extract a single element. +%% +% It is possible to extract a subtensor that contains a single element. +% Observe that singleton dimensions are *not* dropped unless they are +% specifically specified, e.g., as above. +X(1,1,1,:) %<-- Produces a tensor of order 1 and size 1. +%% +% In general, specified dimensions are dropped from the result. Here we +% specify the second and third dimension. +X(:,1,1,:) %<-- Produces a tensor of size 3 x 1. +%% +% Moreover, the subtensor is automatically renumbered/resized in the same +% way that MATLAB works for arrays except that singleton dimensions are +% handled explicitly. +X(1:2,[2 4],1,:) %<-- Produces a tensor of size 2 x 2 x 1. +%% +% It's also possible to extract a list of elements by passing in an array +% of subscripts or a column array of linear indices. +subs = [1,1,1,1; 3,4,2,1]; X(subs) %<-- Extract 2 values by subscript. +%% +inds = [1; 24]; X(inds) %<-- Same thing with linear indices. +%% +% The difference between extracting a subtensor and a list of linear +% indices is ambiguous for 1-dimensional tensors. We can specify 'extract' +% as a second argument whenever we are using a list of subscripts. +X = tenrand(10); %<-- Create a random tensor. +X([1:6]') %<-- Extract a subtensor. +%% +X([1:6]','extract') %<-- Same thing *but* result is a vector. +%% Subscripted assignment for a tensor +% We can assign a single element, an entire subtensor, or a list of values +% for a tensor. +X = tenrand([3,4,2]); %<-- Create some data. +X(1,1,1) = 0 %<-- Replaces the (1,1,1) element. +%% +X(1:2,1:2,1) = ones(2,2) %<-- Replaces a 2 x 2 subtensor. +%% +X([1 1 1;1 1 2]) = [5;7] %<-- Replaces the (1,1,1) and (1,1,2) elements. +%% +X([1;13]) = [5;7] %<-- Same as above using linear indices. +%% +% It is possible to *grow* the tensor automatically by assigning elements +% outside the original range of the tensor. +X(1,1,3) = 1 %<-- Grows the size of the tensor. +%% Using end for the last array index. +X(end,end,end) %<-- Same as X(3,4,3). +%% +X(1,1,1:end-1) %<-- Same as X(1,1,1:2). +%% +% It is also possible to use |end| to index past the end of an array. +X(1,1,end+1) = 5 %<-- Same as X(1,1,4). +%% Use find for subscripts of nonzero elements of a tensor +% The |find| function returns a list of nonzero *subscripts* for a tensor. +% Note that differs from the standard version, which returns linear +% indices. +X = tensor(floor(3*rand(2,2,2))) %<-- Generate some data. +%% +[S,V] = find(X) %<-- Find all the nonzero subscripts and values. +%% +S = find(X >= 2) %<-- Find subscripts of values >= 2. +%% +V = X(S) %<-- Extract the corresponding values from X. +%% Basic operations (plus, minus, and, or, etc.) on a tensor +% The tensor object supports many basic operations, illustrated here. +A = tensor(floor(3*rand(2,3,2))) +B = tensor(floor(3*rand(2,3,2))) +%% +A & B %<-- Calls and. +%% +A | B %<-- Calls or. +%% +xor(A,B) %<-- Calls xor. +%% +A==B %<-- Calls eq. +%% +A~=B %<-- Calls neq. +%% +A>B %<-- Calls gt. +%% +A>=B %<-- Calls ge. +%% +A 0.9) %<-- Extract subscipts of values greater than 0.9. +V = X(S) %<-- Extract the corresponding values. +Y = sptensor(S,V,[5 4 2]) %<-- Create a new tensor. +%% Use ndims and size to get the size of a sptensor +ndims(Y) %<-- Number of dimensions or modes. +%% +size(Y) %<-- Size of Y. +%% +size(Y,3) %<-- Size of mode 3 of Y. +%% Use nnz to get the number of nonzeros of a sptensor +nnz(Y) %<-- Number of nonzeros in Y. +%% Subscripted reference for a sptensor +X = sptensor([4,4,4;2,2,1;2,3,2],[3;5;1],[4 4 4]) %<-- Create a sptensor. +%% +X(1,2,1) %<-- Extract the (1,2,1) element, which is zero. +%% +X(4,4,4) %<-- Extract the (4,4,4) element, which is nonzero. +%% +X(1:2,2:4,:) %<-- Extract a 2 x 3 x 4 subtensor. +%% +X([1 1 1; 2 2 1]) %<-- Extract elements by subscript. +%% +X([1;6]) %<-- Same as above but with linear indices. +%% +% As with a tensor, subscriped reference may be ambiguous for +% one-dimensional tensors. +X = sptensor([1;3;5],1,7) %<-- Create a sparse tensor. +%% +X(3) %<-- Fully specified, single elements are always returned as scalars. +%% +X([3;6]) %<-- Returns a subtensor. +%% +X([3;6],'extract') %<-- Same as above *but* returns an array. +%% Subscripted assignment for a sptensor +X = sptensor([30 40 20]) %<-- Create an emtpy 30 x 40 x 20 sptensor. +%% +X(30,40,20) = 7 %<-- Assign a single element. +%% +X([1,1,1;2,2,2]) = [1;1] %<-- Assign a list of elements. +%% +X(11:20,11:20,11:20) = sptenrand([10,10,10],10) %<-- Assign a subtensor. +%% +X(31,41,21) = 4 %<-- Grows the size of the sptensor. +%% +X(111:120,111:120,111:120) = sptenrand([10,10,10],10) %<-- Grow more. +%% Use end as the last index. +X(end-10:end,end-10:end,end-5:end) %<-- Same as X(108:118,110:120,115:120) +%% Use elemfun to manipulate the nonzeros of a sptensor +% The function |elemfun| is similar to |spfun| for sparse matrices. +X = sptenrand([10,10,10],3) %<-- Create some data. +%% +Z = elemfun(X, @sqrt) %<-- Square root of every nonzero. +%% +Z = elemfun(X, @(x) x+1) %<-- Use a custom function. +%% +Z = elemfun(X, @(x) x~=0) %<-- Set every nonzero to one. +%% +Z = ones(X) %<-- An easier way to change every nonzero to one. +%% Basic operations (plus, minus, times, etc.) on a sptensor +A = sptensor(tensor(floor(5*rand(2,2,2)))) %<-- Create data. +B = sptensor(tensor(floor(5*rand(2,2,2)))) %<-- Create more data. +%% ++A %<-- Calls uplus. +%% +-A %<-- Calls uminus. +%% +A+B %<-- Calls plus. +%% +A-B %<-- Calls minus. +%% +A.*B %<-- Calls times. +%% +5*A %<-- Calls mtimes. +%% +A./2 %<-- Calls rdivide. +%% +% Elementwise divsion by another sptensor is allowed, but +% if the sparsity pattern of the denominator should be a +% superset of the numerator. +A./(A+B) %<-- Calls rdivide. +%% +A./B %<-- Uh-oh. Getting a divide by zero. +%% Use permute to reorder the modes of a sptensor +A = sptenrand([30 40 20 1], 5) %<-- Create data. +%% +permute(A,[4 3 2 1]) %<-- Reorder the modes. +%% +% Permute works correctly for a 1-dimensional sptensor. +X = sptenrand(40,4) %<-- Create data. +%% +permute(X,1) %<-- Permute. +%% Displaying a tensor +% The function |disp| handles small and large elements appropriately, as +% well as aligning the indices. +X = sptensor([1 1 1]); %<-- Create an empty sptensor. +X(1,1,1) = rand(1)*1e15; %<-- Insert a very big element. +X(4,3,2) = rand(1)*1e-15; %<-- Insert a very small element. +X(2,2,2) = rand(1); %<-- Insert a 'normal' element. +disp(X) diff --git a/external/tensor_toolbox_2.5/doc/B1_tenmat_doc.m b/external/tensor_toolbox_2.5/doc/B1_tenmat_doc.m new file mode 100755 index 0000000..785ff95 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/B1_tenmat_doc.m @@ -0,0 +1,81 @@ +%% Converting a tensor to a matrix and vice versa +% We show how to convert a tensor to a matrix stored with extra information +% so that it can be converted back to a tensor. Converting to a matrix +% requies an ordered mapping of the tensor indices to the rows and the +% columns of the matrix. +%% Creating a tenmat (tensor as matrix) object +X = tensor(1:24,[3 2 2 2]) %<-- Create a tensor. +%% +A = tenmat(X,[1 2],[3 4]) %<-- Dims [1 2] map to rows, [3 4] to columns. +%% +B = tenmat(X,[2 1],[3 4]) %<-- Order matters! +%% +C = tenmat(X,[1 2],[4 3]) %<-- Order matters! +%% Creating a tenmat by specifying the dimensions mapped to the rows +% If just the row indices are specified, then the columns are arranged in +% increasing order. +A = tenmat(X,1) %<-- Same as A = tenmat(X,1,2:4) +%% Creating a tenmat by specifying the dimensions mapped to the columns +% Likewise, just the columns can be specified if the 3rd argument is a 't'. +% The rows are arranged in increasing order. +A = tenmat(X, [2 3], 't') %<-- Same as A = tenmat(X,[1 4],[2 3]). +%% Vectorize via tenmat +% All the dimensions can be mapped to the rows or the columnns. +A = tenmat(X,1:4,'t') %<-- Map all the dimensions to the columns +%% Alternative ordering for the columns for mode-n matricization +% Mode-n matricization means that only mode n is mapped to the rows. +% Different column orderings are available. +A = tenmat(X,2) %<-- By default, columns are ordered as [1 3 4]. +%% +A = tenmat(X,2,[3 1 4]) %<-- Explicit specification. +%% +A = tenmat(X,2,'fc') %<-- Forward cyclic, i.e., [3 4 1]. +%% +A = tenmat(X,2,'bc') %<-- Backward cyclic, i.e., [1 4 3]. +%% Constituent parts of a tenmat +A.data %<-- The matrix itself. +%% +A.tsize %<-- Size of the original tensor. +%% +A.rdims %<-- Dimensions that were mapped to the rows. +%% +A.cdims %<-- Dimensions that were mapped to the columns. +%% Creating a tenmat from its constituent parts +B = tenmat(A.data,A.rdims,A.cdims,A.tsize) %<-- Recreates A +%% Creating an empty tenmat +B = tenmat %<-- Empty tenmat. +%% Use double to convert a tenmat to a MATLAB matrix +double(A) %<-- converts A to a standard matrix +%% Use tensor to convert a tenmat to a tensor +Y = tensor(A) +%% Use size and tsize for the dimensions of a tenmat +size(A) %<-- Matrix size +tsize(A) %<-- Corresponding tensor size +%% Subscripted reference for a tenmat +A(2,1) %<-- returns the (2,1) element of the matrix. +%% Subscripted assignment for a tenmat +A(1:2,1:2) = ones(2) %<-- Replace part of the matrix. +%% Use end for the last index +A(end,end) %<-- Same as X(2,12) +%% Basic operations for tenmat +norm(A) %<-- Norm of the matrix. +%% +A' %<-- Calls ctranspose (also swaps mapped dimensions). +%% ++A %<-- Calls uplus. +%% +-A %<-- Calls uminus. +%% +A+A %<-- Calls plus. +%% +A-A %<-- Calls minus. +%% Multiplying two tenmats +% It is possible to compute the product of two tenmats and have a result +% that can be converted into a tensor. +B = A * A' %<-- Tenmat that is the product of two tenmats. +%% +tensor(B) %<-- Corresponding tensor. +%% Displaying a tenmat +% Shows the original tensor dimensions, the modes mapped to rows, the modes +% mapped to columns, and the matrix. +disp(A) diff --git a/external/tensor_toolbox_2.5/doc/B2_sptenmat_doc.m b/external/tensor_toolbox_2.5/doc/B2_sptenmat_doc.m new file mode 100755 index 0000000..69d079c --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/B2_sptenmat_doc.m @@ -0,0 +1,88 @@ +%% Converting sparse tensors to matrices and vice versa +% We show how to convert a sptensor to a matrix stored in _coordinate_ +% format and with extra information so that it can be converted back to a +% sptensor. + +%% Creating a sptenmat (sparse tensor as sparse matrix) object +% A sparse tensor can be converted to a sparse matrix. The matrix, however, +% is not stored as a MATLAB sparse matrix because that format is sometimes +% inefficient for converted sparse tensors. Instead, the row and column +% indices are stored explicitly. +%% +% First, we create a sparse tensor to be converted. +X = sptenrand([10 10 10 10],10) %<-- Generate some data. +%% +% All the same options for tenmat are available as for tenmat. +A = sptenmat(X,1) %<-- Mode-1 matricization. +%% +A = sptenmat(X,[2 3]) %<-- More than one mode is mapped to the columns. +%% +A = sptenmat(X,[2 3],'t') %<-- Specify column dimensions (transpose). +%% +A = sptenmat(X,1:4) %<-- All modes mapped to rows, i.e., vectorize. +%% +A = sptenmat(X,2) %<-- By default, columns are ordered as [1 3 4]. +%% +A = sptenmat(X,2,[3 1 4]) %<-- Explicit column ordering. +%% +A = sptenmat(X,2,'fc') %<-- Foward cyclic. +%% +A = sptenmat(X,2,'bc') %<-- Backward cyclic. +%% Constituent parts of a sptenmat +A.subs %<-- Subscripts of the nonzeros. +%% +A.vals %<-- The corresponding nonzero values. +%% +A.tsize %<-- Size of the original tensor. +%% +A.rdims %<-- Dimensions that were mapped to the rows. +%% +A.cdims %<-- Dimensions that were mapped to the columns. +%% Creating a sptenmat from its constituent parts +B = sptenmat(A.subs,A.vals,A.rdims,A.cdims,A.tsize) %<-- Copies A +%% +B = sptenmat(double(A),A.rdims,A.cdims,A.tsize) %<-- More efficient to pass a matrix. +%% Creating a sptenmat with no nonzeros +A = sptenmat([],[],A.rdims,A.cdims,A.tsize) %<-- An empty sptenmat. +%% Creating an emtpy sptenmat +A = sptenmat %<-- A really empty sptenmat. +%% Use double to convert a sptenmat to a MATLAB sparse matrix +X = sptenrand([10 10 10 10],10); %<-- Create a tensor. +A = sptenmat(X,1) %<-- Convert it to a sptenmat +%% +B = double(A) %<-- Convert it to a MATLAB sparse matrix +%% +whos A B %<-- The storage for B (the sparse matrix) is larger than for A. +%% +C = B'; %<-- Transposing the result fixes the problem. +whos C +%% Use full to convert a sptenmat to a tenmat +B = sptenmat(sptenrand([3 3 3], 3), 1) %<-- Create a sptenmat +%% +C = full(B) %<-- Convert to a tenmat +%% Use sptensor to convert a sptenmat to a sptensor +Y = sptensor(A) %<-- Convert a sptenmat to a sptensor +%% Use size and tsize for the dimensions of a sptenmat +size(A) %<-- Matrix size +tsize(A) %<-- Corresponding tensor size +%% Subscripted reference for a sptenmat +% This is not supported beyond getting the constituent parts. +%% Subscripted assignment for a sptenmat +A(1:2,1:2) = ones(2) %<-- Replace part of the matrix. +%% Use end for the last index +% End is not supported. +%% Basic operations for sptenmat +norm(A) %<-- Norm of the matrix. +%% ++A %<-- Calls uplus. +%% +-A %<-- Calls uminus. +%% Use aatx to efficiently compute A * A' * x for a sptenmat +x = ones(10,1); %<-- Create vector +aatx(A,x) %<-- Compute A * A' * x +%% +double(A) * double(A)' * x %<-- Same as above but less efficient +%% Displaying a tenmat +% Shows the original tensor dimensions, the modes mapped to rows, the modes +% mapped to columns, and the matrix. +disp(A) diff --git a/external/tensor_toolbox_2.5/doc/C_ttensor_doc.m b/external/tensor_toolbox_2.5/doc/C_ttensor_doc.m new file mode 100755 index 0000000..df140b8 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/C_ttensor_doc.m @@ -0,0 +1,77 @@ +%% Tucker Tensors +% Tucker format is a decomposition of a tensor X as the product of a core +% tensor G and matrices (e.g., A,B,C) in each dimension. In other words, a +% tensor X is expressed as: +% +% $${\mathcal X} = {\mathcal G} \times_1 A \times_2 B \times_2 C$$ +% +% In MATLAB notation, |X=ttm(G,{A,B,C})|. The |ttensor| class stores the +% components of the tensor X and can perform many operations, e.g., |ttm|, +% without explicitly forming the tensor X. +%% Creating a ttensor with a tensor core +core = tensor(rand(3,2,1),[3 2 1]); %<-- The core tensor. +U = {rand(5,3), rand(4,2), rand(3,1)}; %<-- The matrices. +X = ttensor(core,U) %<-- Create the ttensor. +%% Alternate core formats: sptensor, ktensor, or ttensor +core1 = sptenrand([3 2 1],3); %<-- Create a 3 x 2 x 1 sptensor. +Y = ttensor(core1,U) %<-- Core is a sptensor. +%% +V = {rand(3,2),rand(2,2),rand(1,2)}; %<-- Create some random matrices. +core2 = ktensor(V); %<-- Create a 3 x 2 x 1 ktensor. +Y = ttensor(core2,U) %<-- Core is a ktensor. +%% +core3 = ttensor(tensor(1:8,[2 2 2]),V); %<-- Create a 3 x 2 x 1 ttensor. +Y = ttensor(core3,U) %<-- Core is a ttensor. +%% Creating a one-dimensional ttensor +Z = ttensor(tensor(rand(2,1),2), rand(4,2)) %<-- One-dimensional ttensor. +%% Constituent parts of a ttensor +X.core %<-- Core tensor. +%% +X.U %<-- Cell array of matrices. +%% Creating a ttensor from its constituent parts +Y = ttensor(X.core,X.U) %<-- Recreate a tensor from its parts. +%% Creating an empty ttensor. +X = ttensor %<-- empty ttensor +%% Use full or tensor to convert a ttensor to a tensor +X = ttensor(core,U) %<-- Create a tensor +%% +full(X) %<-- Converts to a tensor. +%% +tensor(X) %<-- Also converts to a tensor. +%% Use double to convert a ttensor to a (multidimensional) array +double(X) %<-- Converts to a MATLAB array +%% Use ndims and size to get the size of a ttensor +ndims(X) %<-- Number of dimensions. +%% +size(X) %<-- Row vector of the sizes. +%% +size(X,2) %<-- Size of the 2nd mode. +%% Subscripted reference to a ttensor +X.core(1,1,1) %<-- Access an element of the core. +%% +X.U{2} %<-- Extract a matrix. +%% +X{2} %<-- Same as above. +%% Subscripted assignment for a ttensor +X.core = tenones(size(X.core)) %<-- Insert a new core. +%% +X.core(2,2,1) = 7 %<-- Change a single element. +%% +X{3}(1:2,1) = [1;1] %<-- Change the matrix for mode 3. +%% Using end for last index +X{end} %<-- The same as X{3}. +%% Basic operations (uplus, uminus, mtimes) for a ttensor. +X = ttensor(tenrand([2 2 2]),{rand(3,2),rand(1,2),rand(2,2)}) %<-- Data. ++X %<-- Calls uplus. +%% +-X %<-- Calls uminus. +%% +5*X %<-- Calls mtimes. +%% Use permute to reorder the modes of a ttensor +permute(X,[3 2 1]) %<-- Reverses the modes of X +%% Displaying a ttensor +% The tensor displays by displaying the core and each of the component +% matrices. +disp(X) %<-- Prints out the ttensor. + + diff --git a/external/tensor_toolbox_2.5/doc/D_ktensor_doc.m b/external/tensor_toolbox_2.5/doc/D_ktensor_doc.m new file mode 100755 index 0000000..97a1a6a --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/D_ktensor_doc.m @@ -0,0 +1,147 @@ +%% Kruskal tensors +% Kruskal format is a decomposition of a tensor X as the sum of the outer +% products a the columns of matrices. For example, we might write +% +% $${\mathcal X} = \sum_r a_r \circ b_r \circ c_r$$ +% +% where a subscript denotes column index and a circle denotes outer +% product. In other words, the tensor X is built frm the columns of the +% matrices A,B, and C. It's often helpful to explicitly specify a weight +% for each outer product, which we do here: +% +% $${\mathcal X} = \sum_r \lambda_r \; a_r \circ b_r \circ c_r$$ +% +% The |ktensor| class stores the components of the tensor X and can perform +% many operations, e.g., |ttm|, without explicitly forming the tensor X. + +%% Kruskal tensor format via ktensor +% Kruskal format stores a tensor as a sum of rank-1 outer products. For +% example, consider a tensor of the following form. +% +% $$X = a_1 \circ b_1 \circ c_1 + a_2 \circ b_2 \circ c_2$$ +% +% This can be stored in Kruskal form as follows. +rand('state',0); +A = rand(4,2); %<-- First column is a_1, second is a_2. +B = rand(3,2); %<-- Likewise for B. +C = rand(2,2); %<-- Likewise for C. +X = ktensor({A,B,C}) %<-- Create the ktensor. +%% +% For Kruskal format, there can be any number of matrices, but every matrix +% must have the same number of columns. The number of rows can vary. +Y = ktensor({rand(4,1),rand(2,1),rand(3,1)}) %<-- Another ktensor. +%% Specifying weights in a ktensor +% Weights for each rank-1 tensor can be specified by passing in a +% column vector. For example, +% +% $$X = \lambda_1 \; a_1 \circ b_1 \circ c_1 + \lambda_2 \; a_2 \circ b_2 \circ c_2$$ +% +lambda = [5.0; 0.25]; %<-- Weights for each factor. +X = ktensor(lambda,{A,B,C}) %<-- Create the ktensor. +%% Creating a one-dimensional ktensor +Y = ktensor({rand(4,5)}) %<-- A one-dimensional ktensor. +%% Constituent parts of a ktensor +X.lambda %<-- Weights or multipliers. +%% +X.U %<-- Cell array of matrices. +%% Creating a ktensor from its constituent parts +Y = ktensor(X.lambda,X.U) %<-- Recreate X. +%% Creating an empty ktensor +Z = ktensor %<-- Empty ktensor. +%% Use full or tensor to convert a ktensor to a tensor +full(X) %<-- Converts to a tensor. +%% +tensor(X) %<-- Same as above. +%% Use double to convert a ktensor to a multidimensional array +double(X) %<-- Converts to an array. +%% Use tendiag or sptendiag to convert a ktensor to a ttensor. +% A ktensor can be regarded as a ttensor with a diagonal core. +R = length(X.lambda); %<-- Number of factors in X. +core = tendiag(X.lambda, repmat(R,1,ndims(X))); %<-- Create a diagonal core. +Y = ttensor(core, X.u) %<-- Assemble the ttensor. +%% +norm(full(X)-full(Y)) %<-- They are the same. +%% +core = sptendiag(X.lambda, repmat(R,1,ndims(X))); %<-- Sparse diagonal core. +Y = ttensor(core, X.u) %<-- Assemble the ttensor +%% +norm(full(X)-full(Y)) %<-- They are the same. +%% Use ndims and size for the dimensions of a ktensor +ndims(X) %<-- Number of dimensions. +%% +size(X) %<-- Row vector of the sizes. +%% +size(X,2) %<-- Size of the 2nd mode. +%% Subscripted reference for a ktensor +X(1,1,1) %<-- Assemble the (1,1,1) element (requires computation). +%% +X.lambda(2) %<-- Weight of 2nd factor. +%% +X.U{2} %<-- Extract a matrix. +%% +X{2} %<-- Same as above. +%% Subscripted assignment for a ktensor +X.lambda = ones(size(X.lambda)) %<-- Insert new multipliers. +%% +X.lambda(1) = 7 %<-- Change a single element of lambda. +%% +X{3}(1:2,1) = [1;1] %<-- Change the matrix for mode 3. +%% Use end for the last array index. +X(3:end,1,1) %<-- Calculated X(3,1,1) and X((4,1,1). +%% +X(1,1,1:end-1) %<-- Calculates X(1,1,1). +%% +X{end} %<-- Or use inside of curly braces. This is X{3}. +%% Adding and subtracting ktensors +% Adding two ktensors is the same as concatenating the matrices +X = ktensor({rand(4,2),rand(2,2),rand(3,2)}) %<-- Data. +Y = ktensor({rand(4,2),rand(2,2),rand(3,2)}) %<-- More data. +%% +Z = X + Y %<-- Concatenates the factor matrices. +%% +Z = X - Y %<-- Concatenates as with plus, but changes the weights. +%% +norm( full(Z) - (full(X)-full(Y)) ) %<-- Should be zero. +%% Basic operations with a ktensor ++X %<-- Calls uplus. +%% +-X %<-- Calls uminus. +%% +5*X %<-- Calls mtimes. +%% Use permute to reorder the modes of a ktensor +permute(X,[2 3 1]) %<-- Reorders modes of X +%% Use arrange to normalize the factors of a ktensor +% The function |arrange| normalizes the columns of the factors and then +% arranges the rank-one pieces in decreasing order of size. +X = ktensor({rand(3,2),rand(4,2),rand(2,2)}) % <-- Unit weights. +%% +arrange(X) %<-- Normalized a rearranged. +%% Use fixsigns for sign indeterminacies in a ktensor +% The largest magnitude entry for each factor is changed to be +% positive provided that we can flip the signs of _pairs_ of vectors in +% that rank-1 component. +Y = X; +Y.u{1}(:,1) = -Y.u{1}(:,1); % switch the sign on a pair of columns +Y.u{2}(:,1) = -Y.u{2}(:,1) +%% +fixsigns(Y) +%% Use ktensor to store the 'skinny' SVD of a matrix +A = rand(4,3) %<-- A random matrix. +%% +[U,S,V] = svd(A,0); %<-- Compute the SVD. +X = ktensor(diag(S),{U,V}) %<-- Store the SVD as a ktensor. +%% +double(X) %<-- Reassemble the original matrix. +%% Displaying a ktensor +disp(X) %<-- Displays the vector lambda and each factor matrix. +%% Displaying data +% The |datadisp| function allows the user to associate meaning to the modes +% and display those modes with the most meaning (i.e., corresponding to the +% largest values). +X = ktensor({[0.8 0.1 1e-10]',[1e-5 2 3 1e-4]',[0.5 0.5]'}); %<-- Create tensor. +X = arrange(X) %<-- Normalize the factors. +%% +labelsDim1 = {'one','two','three'}; %<-- Labels for mode 1. +labelsDim2 = {'A','B','C','D'}; %<-- Labels for mode 2. +labelsDim3 = {'on','off'}; %<-- Labels for mode 3. +datadisp(X,{labelsDim1,labelsDim2,labelsDim3}) %<-- Display. \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/M1_multiply_doc.m b/external/tensor_toolbox_2.5/doc/M1_multiply_doc.m new file mode 100755 index 0000000..aee2547 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/M1_multiply_doc.m @@ -0,0 +1,274 @@ +%% Multiplying tensors + +%% Tensor times vector (ttv for tensor) +% Compute a tensor times a vector (or vectors) in one (or more) modes. +rand('state',0); +X = tenrand([5,3,4,2]); %<-- Create a dense tensor. +A = rand(5,1); B = rand(3,1); C = rand(4,1); D = rand(2,1); %<-- Some vectors. +%% +Y = ttv(X, A, 1) %<-- X times A in mode 1. +%% +Y = ttv(X, {A,B,C,D}, 1) %<-- Same as above. +%% +Y = ttv(X, {A,B,C,D}, [1 2 3 4]) %<-- All-mode multiply produces a scalar. +%% +Y = ttv(X, {D,C,B,A}, [4 3 2 1]) %<-- Same as above. +%% +Y = ttv(X, {A,B,C,D}) %<-- Same as above. +%% +Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4. +%% +Y = ttv(X, {A,B,C,D}, [3 4]) %<-- Same as above. +%% +Y = ttv(X, {A,B,D}, [1 2 4]) %<-- 3-way multiplication. +%% +Y = ttv(X, {A,B,C,D}, [1 2 4]) %<-- Same as above. +%% +Y = ttv(X, {A,B,D}, -3) %<-- Same as above. +%% +Y = ttv(X, {A,B,C,D}, -3) %<-- Same as above. +%% Sparse tensor times vector (ttv for sptensor) +% This is the same as in the dense case, except that the result may be +% either dense or sparse (or a scalar). +X = sptenrand([5,3,4,2],5); %<-- Create a sparse tensor. +%% +Y = ttv(X, A, 1) %<-- X times A in mode 1. Result is sparse. +%% +Y = ttv(X, {A,B,C,D}, [1 2 3 4]) %<-- All-mode multiply. +%% +Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4. +%% +Y = ttv(X, {A,B,D}, -3) %<-- 3-way multiplication. Result is *dense*! +%% Kruskal tensor times vector (ttv for ktensor) +% The special structure of a ktensor allows an efficient implementation of +% vector multiplication. The result is a ktensor or a scalar. +X = ktensor([10;1],rand(5,2),rand(3,2),rand(4,2),rand(2,2)); %<-- Ktensor. +Y = ttv(X, A, 1) %<-- X times A in mode 1. Result is a ktensor. +%% +norm(full(Y) - ttv(full(X),A,1)) %<-- Result is the same as dense case. +%% +Y = ttv(X, {A,B,C,D}) %<-- All-mode multiply -- scalar result. +%% +Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4. +%% +Y = ttv(X, {A,B,D}, [1 2 4]) %<-- 3-way multiplication. +%% Tucker tensor times vector (ttv for ttensor) +% The special structure of a ttensor allows an efficient implementation of +% vector multiplication. The result is a ttensor or a scalar. +X = ttensor(tenrand([2,2,2,2]),rand(5,2),rand(3,2),rand(4,2),rand(2,2)); +Y = ttv(X, A, 1) %<-- X times A in mode 1. +%% +norm(full(Y) - ttv(full(X),A, 1)) %<-- Same as dense case. +%% +Y = ttv(X, {A,B,C,D}, [1 2 3 4]) %<-- All-mode multiply -- scalar result. +%% +Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4. +%% +Y = ttv(X, {A,B,D}, [1 2 4]) %<-- 3-way multiplication. +%% Tensor times matrix (ttm for tensor) +% Compute a tensor times a matrix (or matrices) in one (or more) modes. +X = tensor(rand(5,3,4,2)); +A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2); +%% +Y = ttm(X, A, 1); %<-- X times A in mode-1. +Y = ttm(X, {A,B,C,D}, 1); %<-- Same as above. +Y = ttm(X, A', 1, 't') %<-- Same as above. +%% +Y = ttm(X, {A,B,C,D}, [1 2 3 4]); %<-- 4-way mutliply. +Y = ttm(X, {D,C,B,A}, [4 3 2 1]); %<-- Same as above. +Y = ttm(X, {A,B,C,D}); %<-- Same as above. +Y = ttm(X, {A',B',C',D'}, 't') %<-- Same as above. +%% +Y = ttm(X, {C,D}, [3 4]); %<-- X times C in mode-3 & D in mode-4 +Y = ttm(X, {A,B,C,D}, [3 4]) %<-- Same as above. +%% +Y = ttm(X, {A,B,D}, [1 2 4]); %<-- 3-way multiply. +Y = ttm(X, {A,B,C,D}, [1 2 4]); %<-- Same as above. +Y = ttm(X, {A,B,D}, -3); %<-- Same as above. +Y = ttm(X, {A,B,C,D}, -3) %<-- Same as above. +%% Sparse tensor times matrix (ttm for sptensor) +% It is also possible to multiply an sptensor times a matrix or series of +% matrices. The arguments are the same as for the dense case. The result may +% be dense or sparse, depending on its density. +X = sptenrand([5 3 4 2],10); +Y = ttm(X, A, 1); %<-- X times A in mode-1. +Y = ttm(X, {A,B,C,D}, 1); %<-- Same as above. +Y = ttm(X, A', 1, 't') %<-- Same as above +%% +norm(full(Y) - ttm(full(X),A, 1) ) %<-- Same as dense case. +%% +Y = ttm(X, {A,B,C,D}, [1 2 3 4]); %<-- 4-way multiply. +Y = ttm(X, {D,C,B,A}, [4 3 2 1]); %<-- Same as above. +Y = ttm(X, {A,B,C,D}); %<-- Same as above. +Y = ttm(X, {A',B',C',D'}, 't') %<-- Same as above. +%% +Y = ttm(X, {C,D}, [3 4]); %<-- X times C in mode-3 & D in mode-4 +Y = ttm(X, {A,B,C,D}, [3 4]) %<-- Same as above. +%% +Y = ttm(X, {A,B,D}, [1 2 4]); %<-- 3-way multiply. +Y = ttm(X, {A,B,C,D}, [1 2 4]); %<-- Same as above. +Y = ttm(X, {A,B,D}, -3); %<-- Same as above. +Y = ttm(X, {A,B,C,D}, -3) %<-- Same as above. +%% +% The result may be dense or sparse. +X = sptenrand([5 3 4],1); +Y = ttm(X, A, 1) %<-- Sparse result. +%% +X = sptenrand([5 3 4],50); +Y = ttm(X, A, 1) %<-- Dense result. +%% +% Sometimes the product may be too large to reside in memory. For +% example, try the following: +% X = sptenrand([100 100 100 100], 1e4); +% A = rand(1000,100); +% ttm(X,A,1); %<-- too large for memory +%% Kruskal tensor times matrix (ttm for ktensor) +% The special structure of a ktensor allows an efficient implementation of +% matrix multiplication. The arguments are the same as for the dense case. +X = ktensor({rand(5,1) rand(3,1) rand(4,1) rand(2,1)}); +%% +Y = ttm(X, A, 1); %<-- X times A in mode-1. +Y = ttm(X, {A,B,C,D}, 1); %<-- Same as above. +Y = ttm(X, A', 1, 't') %<-- Same as above. +%% +Y = ttm(X, {A,B,C,D}, [1 2 3 4]); %<-- 4-way mutliply. +Y = ttm(X, {D,C,B,A}, [4 3 2 1]); %<-- Same as above. +Y = ttm(X, {A,B,C,D}); %<-- Same as above. +Y = ttm(X, {A',B',C',D'}, 't') %<-- Same as above. +%% +Y = ttm(X, {C,D}, [3 4]); %<-- X times C in mode-3 & D in mode-4. +Y = ttm(X, {A,B,C,D}, [3 4]) %<-- Same as above. +%% +Y = ttm(X, {A,B,D}, [1 2 4]); %<-- 3-way multiply. +Y = ttm(X, {A,B,C,D}, [1 2 4]); %<-- Same as above. +Y = ttm(X, {A,B,D}, -3); %<-- Same as above. +Y = ttm(X, {A,B,C,D}, -3) %<-- Same as above. +%% Tucker tensor times matrix (ttm for ttensor) +% The special structure of a ttensor allows an efficient implementation of +% matrix multiplication. +X = ttensor(tensor(rand(2,2,2,2)),{rand(5,2) rand(3,2) rand(4,2) rand(2,2)}); +%% +Y = ttm(X, A, 1); %<-- computes X times A in mode-1. +Y = ttm(X, {A,B,C,D}, 1); %<-- Same as above. +Y = ttm(X, A', 1, 't') %<-- Same as above. +%% +Y = ttm(X, {A,B,C,D}, [1 2 3 4]); %<-- 4-way multiply. +Y = ttm(X, {D,C,B,A}, [4 3 2 1]); %<-- Same as above. +Y = ttm(X, {A,B,C,D}); %<-- Same as above. +Y = ttm(X, {A',B',C',D'}, 't') %<-- Same as above. +%% +Y = ttm(X, {C,D}, [3 4]); %<-- X times C in mode-3 & D in mode-4 +Y = ttm(X, {A,B,C,D}, [3 4]) %<-- Same as above. +%% +Y = ttm(X, {A,B,D}, [1 2 4]); %<-- 3-way multiply +Y = ttm(X, {A,B,C,D}, [1 2 4]); %<-- Same as above. +Y = ttm(X, {A,B,D}, -3); %<-- Same as above. +Y = ttm(X, {A,B,C,D}, -3) %<-- Same as above. +%% Tensor times tensor (ttt for tensor) +X = tensor(rand(4,2,3)); Y = tensor(rand(3,4,2)); +Z = ttt(X,Y); %<-- Outer product of X and Y. +size(Z) +%% +Z = ttt(X,X,1:3) %<-- Inner product of X with itself. +%% +Z = ttt(X,Y,[1 2 3],[2 3 1]) %<-- Inner product of X & Y. +%% +Z = innerprod(X,Y) %<-- Same as above. +%% +Z = ttt(X,Y,[1 3],[2 1]) %<-- Product of X & Y along specified dims. +%% Sparse tensor times sparse tensor (ttt for sptensor) +X = sptenrand([4 2 3],3); Y = sptenrand([3 4 2],3); +Z = ttt(X,Y) %<--Outer product of X and Y. +%% +norm(full(Z)-ttt(full(X),full(Y))) %<-- Same as dense. +%% +Z = ttt(X,X,1:3) %<-- Inner product of X with itself. +%% +X = sptenrand([2 3],1); Y = sptenrand([3 2],1); +Z = ttt(X, Y) %<-- Sparse result. +%% +X = sptenrand([2 3],20); Y = sptenrand([3 2],20); +Z = ttt(X, Y) %<-- Dense result. +%% +Z = ttt(X,Y,[1 2],[2 1]) %<-- inner product of X & Y +%% Inner product (innerprod) +% The function |innerprod| efficiently computes the inner product +% between two tensors X and Y. The code does this efficiently +% depending on what types of tensors X and Y. +X = tensor(rand(2,2,2)) +Y = ktensor({rand(2,2),rand(2,2),rand(2,2)}) +%% +z = innerprod(X,Y) +%% Contraction on tensors (contract for tensor) +% The function |contract| sums the entries of X along dimensions I and +% J. Contraction is a generalization of matrix trace. In other words, +% the trace is performed along the two-dimensional slices defined by +% dimensions I and J. It is possible to implement tensor +% multiplication as an outer product followed by a contraction. +X = sptenrand([4 3 2],5); +Y = sptenrand([3 2 4],5); +%% +Z1 = ttt(X,Y,1,3); %<-- Normal tensor multiplication +%% +Z2 = contract(ttt(X,Y),1,6); %<-- Outer product + contract +%% +norm(Z1-Z2) %<-- Should be zero +%% +% Using |contract| on either sparse or dense tensors gives the same +% result +X = sptenrand([4 2 3 4],20); +Z1 = contract(X,1,4) % sparse version of contract +%% +Z2 = contract(full(X),1,4) % dense version of contract +%% +norm(full(Z1) - Z2) %<-- Should be zero +%% +% The result may be dense or sparse, depending on its density. +X = sptenrand([4 2 3 4],8); +Y = contract(X,1,4) %<-- should be sparse +%% +X = sptenrand([4 2 3 4],80); +Y = contract(X,1,4) %<-- should be dense +%% Relationships among ttv, ttm, and ttt +% The three "tensor times ___" functions (|ttv|, |ttm|, |ttt|) all perform +% specialized calculations, but they are all related to some degree. +% Here are several relationships among them: +%% +X = tensor(rand(4,3,2)); +A = rand(4,1); +%% +% Tensor times vector gives a 3 x 2 result +Y1 = ttv(X,A,1) +%% +% When |ttm| is used with the transpose option, the result is almost +% the same as |ttv| +Y2 = ttm(X,A,1,'t') +%% +% We can use |squeeze| to remove the singleton dimension left over +% from |ttm| to give the same answer as |ttv| +squeeze(Y2) +%% +% Tensor outer product may be used in conjuction with contract to +% produce the result of |ttm|. Please note that this is more expensive +% than using |ttm|. +Z = ttt(tensor(A),X); +size(Z) +%% +Y3 = contract(Z,1,3) +%% +% Finally, use |squeeze| to remove the singleton dimension to get +% the same result as |ttv|. +squeeze(Y3) +%% Frobenius norm of a tensor +% The Frobenius norm of any type of tensor may be computed with the +% function |norm|. Each class is optimized to calculate the norm +% in the most efficient manner. +X = sptenrand([4 3 2],5) +norm(X) +norm(full(X)) +%% +X = ktensor({rand(4,2),rand(3,2)}) +norm(X) +%% +X = ttensor(tensor(rand(2,2)),{rand(4,2),rand(3,2)}) +norm(X) diff --git a/external/tensor_toolbox_2.5/doc/M2_identities_doc_future.m b/external/tensor_toolbox_2.5/doc/M2_identities_doc_future.m new file mode 100755 index 0000000..1e4ce39 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/M2_identities_doc_future.m @@ -0,0 +1,236 @@ +%% Identities and relationships of tensors +% There are many mathematical relationships, identities, and +% connections among tensors. These identities are presented here and +% show the versatility of the Tensor Toolbox. +% The propositions indicated below are references to the following +% report: +% +% T.G. Kolda, "Multilinear operators for higher-order decompositions", +% Tech. Rep. SAND2006-2081, Sandia National Laboratories, April 2006, +% http://csmr.ca.sandia.gov/~tgkolda/pubs/index.html#SAND2006-2081. + +%% N-mode product properties +% Create some data. +Y = tenrand([4 3 2]); +A = rand(3,4); +B = rand(3,3); +%% +% Prop 3.4(a): The order of the multiplication in different modes is irrelevant. +% +% $$(Y \times_1 A) \times_2 B = (Y \times_2 B) \times_1 A$$ +% +X1 = ttm( ttm(Y,A,1), B, 2); %<-- Y x_1 A x_2 B +X2 = ttm( ttm(Y,B,2), A, 1); %<-- Y x_2 B x_1 A +norm(X1 - X2) %<-- difference is zero +%% N-mode product and matricization +% Generate some data to work with. +Y = tenrand([5 4 3]); +A = rand(4,5); B = rand(3,4); C = rand(2,3); U = {A,B,C}; +%% +% Prop. 3.7a: N-mode multiplication can be expressed in terms of matricized +% tensors. +% +% $$X = Y \times_n U \Leftrightarrow X_{(n)} = UY_{(n)} $$ +% +for n = 1:ndims(Y) + X = ttm(Y,U,n); %<-- X = Y x_n U{n} + Xn = U{n} * tenmat(Y,n); %<-- Xn = U{n} * Yn + norm(tenmat(X,n) - Xn) % <-- should be zero +end +%% +% Prop. 3.7b: We can do matricizations in various ways and still be +% equivalent. +X = ttm(Y,U); %<-- X = Y x_1 A x_2 B x_3 C +Xm1 = kron(B,A)*tenmat(Y,[1 2])*C'; %<-- Kronecker product version +Xm2 = tenmat(X,[1 2]); %<-- Matriczed version +norm(Xm1 - Xm2) % <-- should be zero +Xm1 = B * tenmat(Y,2,[3 1]) * kron(A,C)'; %<-- Kronecker product version +Xm2 = tenmat(X,2,[3 1]); %<-- Matricized version +norm(Xm1 - Xm2) % <-- should be zero +Xm1 = tenmat(Y,[],[1 2 3]) * kron(kron(C,B),A)'; %<-- Vectorized via Kronecker +Xm2 = tenmat(X,[],[1 2 3]); %<-- Vectorized via matricize +norm(Xm1 - Xm2) + +%% Norm of difference between two tensors +% Prop. 3.9: For tensors X and Y, we have: +% +% $$\|X-Y\|^2 = \|X\|^2 + \|Y\|^2 - 2 $$ +% +X = tenrand([5 4 3]); Y = tenrand([5 4 3]); +% The following 2 results should be equal +norm(X-Y) +sqrt(norm(X)^2 - 2*innerprod(X,Y) + norm(Y)^2) +%% +% This relationship makes it more convenient to compare the norm of +% the difference between two different tensor objects. Imagine if we +% have a |sptensor| and a |ktensor| and we want the norm of the +% difference, which may be needed to check for convergence, for +% example, but which is very expensive to convert to a full (dense) +% tensor. Because |innerprod| and |norm| are defined for all types of +% tensor objects, this is a handy formula. +X = sptensor(X); +Y = ktensor({[1:5]',[1:4]',[1:3]'}); +% The following 2 results should be equal +norm(full(X)-full(Y)) +sqrt(norm(X)^2 - 2*innerprod(X,Y) + norm(Y)^2) + +%% Tucker tensor properties +% The properties of the Tucker operator follow directly from the +% properties of n-mode multiplication. + +% Initialize data +Y = tensor(1:24,[4 3 2]); +A1 = reshape(1:20,[5 4]); +A2 = reshape(1:12,[4 3]); +A3 = reshape(1:6,[3 2]); +A = {A1,A2,A3}; +B1 = reshape(1:20,[4 5]); +B2 = reshape(1:12,[3 4]); +B3 = reshape(1:6,[2 3]); +B = {B1,B2,B3}; +%% +% Proposition 4.2a +X = ttensor(ttensor(Y,A),B) +%% +AB = {B1*A1, B2*A2, B3*A3}; +Y = ttensor(Y,AB) +%% +norm(full(X)-full(Y)) %<-- should be zero +%% +% Proposition 4.2b +Y = tensor(1:24,[4 3 2]); +X = ttensor(Y,A); +Apinv = {pinv(A1),pinv(A2),pinv(A3)}; +Y2 = ttensor(full(X),Apinv); +norm(full(Y)-full(Y2)) %<-- should be zero +%% +% Proposition 4.2c +Y = tensor(1:24,[4 3 2]); +rand('state',0); +Q1 = orth(rand(5,4)); +Q2 = orth(rand(4,3)); +Q3 = orth(rand(3,2)); +Q = {Q1,Q2,Q3}; +X = ttensor(Y,Q) +%% +Qt = {Q1',Q2',Q3'}; +Y2 = ttensor(full(X),Qt) +norm(full(Y)-full(Y2)) %<-- should be zero + +%% Tucker operator and matricized tensors +% The Tucker operator also has various epressions in terms of +% matricized tensors and the Kronecker product. +% Proposition 4.3a +Y = tensor(1:24,[4 3 2]); +A1 = reshape(1:20,[5 4]); +A2 = reshape(1:12,[4 3]); +A3 = reshape(1:6,[3 2]); +A = {A1,A2,A3}; +X = ttensor(Y,A) +for n = 1:ndims(Y) + rdims = n; + cdims = setdiff(1:ndims(Y),rdims); + Xn = A{n} * tenmat(Y,rdims,cdims) * kron(A{cdims(2)}, A{cdims(1)})'; + norm(tenmat(full(X),rdims,cdims) - Xn) % <-- should be zero +end + +%% Orthogonalization of Tucker factors +% Proposition 4.4 +Y = tensor(1:24,[4 3 2]); +A1 = rand(5,4); +A2 = rand(4,3); +A3 = rand(3,2); +A = {A1,A2,A3}; +X = ttensor(Y,A) +%% +[Q1,R1] = qr(A1); +[Q2,R2] = qr(A2); +[Q3,R3] = qr(A3); +R = {R1,R2,R3}; +Z = ttensor(Y,R); +norm(X) - norm(Z) %<-- should be zero + +%% Kruskal operator properties +% Proposition 5.2 +A1 = reshape(1:10,[5 2]); +A2 = reshape(1:8,[4 2]); +A3 = reshape(1:6,[3 2]); +K = ktensor({A1,A2,A3}); +B1 = reshape(1:20,[4 5]); +B2 = reshape(1:12,[3 4]); +B3 = reshape(1:6,[2 3]); +X = ttensor(K,{B1,B2,B3}) + +Y = ktensor({B1*A1, B2*A2, B3*A3}); +norm(full(X) - full(Y)) %<-- should be zero + +%% +% Proposition 5.3a (second part) +A1 = reshape(1:10,[5 2]); +A2 = reshape(1:8,[4 2]); +A3 = reshape(1:6,[3 2]); +A = {A1,A2,A3}; +X = ktensor(A); +rdims = 1:ndims(X); +Z = double(tenmat(full(X), rdims, [])); +Xn = khatrirao(A{rdims},'r') * ones(length(X.lambda),1); +norm(Z - Xn) % <-- should be zero +%% +cdims = 1:ndims(X); +Z = double(tenmat(full(X), [], cdims)); +Xn = ones(length(X.lambda),1)' * khatrirao(A{cdims},'r')'; +norm(Z - Xn) % <-- should be zero +%% +% Proposition 5.3b +A1 = reshape(1:10,[5 2]); +A2 = reshape(1:8,[4 2]); +A3 = reshape(1:6,[3 2]); +A = {A1,A2,A3}; +X = ktensor(A); +for n = 1:ndims(X) + rdims = n; + cdims = setdiff(1:ndims(X),rdims); + Xn = khatrirao(A{rdims}) * khatrirao(A{cdims},'r')'; + Z = double(tenmat(full(X),rdims,cdims)); + norm(Z - Xn) % <-- should be zero +end +%% +% Proposition 5.3a (first part) +X = ktensor(A); +for n = 1:ndims(X) + cdims = n; + rdims = setdiff(1:ndims(X),cdims); + Xn = khatrirao(A{rdims},'r') * khatrirao(A{cdims})'; + Z = double(tenmat(full(X),rdims,cdims)); + norm(Z - Xn) % <-- should be zero +end + +%% Norm of Kruskal operator +% The norm of a ktensor has a special form because it can be +% reduced to summing the entries of the Hadamard product of N +% matrices of size R x R. +% Proposition 5.4 +A1 = reshape(1:10,[5 2]); +A2 = reshape(1:8,[4 2]); +A3 = reshape(1:6,[3 2]); +A = {A1,A2,A3}; +X = ktensor(A); +M = ones(size(A{1},2), size(A{1},2)); +for i = 1:numel(A) + M = M .* (A{i}'*A{i}); +end +norm(X) - sqrt(sum(M(:))) %<-- should be zero + +%% Inner product of Kruskal operator with a tensor +% The inner product of a ktensor with a tensor yields +% Proposition 5.5 +X = tensor(1:60,[5 4 3]); +A1 = reshape(1:10,[5 2]); +A2 = reshape(2:9,[4 2]); +A3 = reshape(3:8,[3 2]); +A = {A1,A2,A3}; +K = ktensor(A); +v = khatrirao(A,'r') * ones(size(A{1},2),1); +% The following 2 results should be equal +double(tenmat(X,1:ndims(X),[]))' * v +innerprod(X,K) diff --git a/external/tensor_toolbox_2.5/doc/N_nvecs_doc.m b/external/tensor_toolbox_2.5/doc/N_nvecs_doc.m new file mode 100755 index 0000000..9b7773f --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/N_nvecs_doc.m @@ -0,0 +1,45 @@ +%% Generating the leading mode-n vectors +% The leading mode-n vectors are those vectors that span the subspace of +% the mode-n fibers. In other words, the left singular vectors of the +% n-mode matricization of X. +%% Using nvecs to calculate the leading mode-n vectors +% The |nvecs| command efficient computes the leading n-mode vectors. +rand('state',0); +X = sptenrand([4,3,2],6) %<-- A sparse tensor +%% +nvecs(X,1,2) %<-- The 2 leading mode-1 vectors +%% +nvecs(X,1,3) % <-- The 3 leading mode-1 vectors +%% +nvecs(full(X),1,3) %<-- The same thing for a dense tensor +%% +X = ktensor({rand(3,2),rand(3,2),rand(2,2)}) %<-- A random ktensor +%% +nvecs(X,2,1) %<-- The 1 leading mode-2 vector +%% +nvecs(full(X),2,1) %<-- Same thing for a dense tensor +%% +X = ttensor(tenrand([2,2,2,2]),{rand(3,2),rand(3,2),rand(2,2),rand(2,2)}); %<-- A random ttensor +%% +nvecs(X,4,2) %<-- The 1 leading mode-2 vector +%% +nvecs(full(X),4,2) %<-- Same thing for a dense tensor +%% Using nvecs for the HOSVD +X = tenrand([4 3 2]) %<-- Generate data +%% +U1 = nvecs(X,1,4); %<-- Mode 1 +U2 = nvecs(X,2,3); %<-- Mode 2 +U3 = nvecs(X,3,2); %<-- Mode 3 +S = ttm(X,{pinv(U1),pinv(U2),pinv(U3)}); %<-- Core +Y = ttensor(S,{U1,U2,U3}) %<-- HOSVD of X +%% +norm(full(Y) - X) %<-- Reproduces the same result. + +%% +U1 = nvecs(X,1,2); %<-- Mode 1 +U2 = nvecs(X,2,2); %<-- Mode 2 +U3 = nvecs(X,3,2); %<-- Mode 3 +S = ttm(X,{pinv(U1),pinv(U2),pinv(U3)}); %<-- Core +Y = ttensor(S,{U1,U2,U3}) %<-- Rank-(2,2,2) HOSVD approximation of X +%% +100*(1-norm(full(Y)-X)/norm(X)) %<-- Percentage explained by approximation \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/Q_collapse_scale_doc.m b/external/tensor_toolbox_2.5/doc/Q_collapse_scale_doc.m new file mode 100755 index 0000000..c83bd40 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/Q_collapse_scale_doc.m @@ -0,0 +1,60 @@ +%% Collapsing and scaling tensors +% The tensor and sptensor classes support that notion of collapsing and +% scaling dimensions. + +%% Examples of collapsing a tensor +X = tenrand([4 3 2]) %<-- Generate some data. +%% +Y = collapse(X,[2 3]) %<-- Sum of entries in each mode-1 slice. +%% +Y = collapse(X,-1) %<-- Same as above. +%% +Z = collapse(X,2) %<-- Sum of entries in each row fiber. +%% +collapse(X,1:3) %<-- Sum of all entries. +%% Alternate accumulation functions for tensor +Y = collapse(X,[1 2],@max) %<-- Max entry in each mode-3 slice. +%% +Z = collapse(X,-3,@mean) %<-- Average entry in each mode-3 slice. +%% Examples of collapsing a sptensor +X = sptenrand([4 3 2],6) %<-- Generate some data. +%% +Y = collapse(X,[2 3]) %<-- Sum of entries in each mode-1 slice. +%% +Y = collapse(X,-1) %<-- Same as above. +%% +Z = collapse(X,2) %<-- Sum of entries in each row fiber. +%% +collapse(X,1:3) %<-- Sum of all entries. +%% Alternate accumulation functions for sptensor +Y = collapse(X,[1 2],@min) %<-- Min *nonzero* entry in each mode-3 slice. +%% +Z = collapse(X,-3,@mean) %<-- Average *nonzero* entry in each mode-3 slice. +%% Scaling a tensor in different modes +X = tenones([3,4,5]); %<-- Generate data +S = 10 * [1:5]'; Y = scale(X,S,3) %<-- Scale in mode-3 +%% +S = tensor(10 * [1:5]',5); Y = scale(X,S,3) %<-- First argument is a tensor. +%% +S = tensor(1:12,[3 4]); Y = scale(X,S,[1 2]) %<-- Scale in two modes. +%% +S = tensor(1:12,[3 4]); Y = scale(X,S,-3) %<-- Same as above. +%% +S = tensor(1:60,[3 4 5]); Y = scale(X,S,1:3) %<-- Scale in every mode. +%% +Y = S .* X %<-- Same as above. + +%% Scaling a sptensor in different modes +X = ones(sptenrand([3 4 5], 10)) %<-- Generate data. +%% +S = 10 * [1:5]'; Y = scale(X,S,3) %<-- Scale in one mode. +%% +S = tensor(10 * [1:5]',5); Y = scale(X,S,3) %<-- Same as above. +%% +S = tensor(1:12,[3 4]); Y = scale(X,S,[1 2]) %<-- Scale in two modes. +%% +S = tensor(1:12,[3 4]); Y = scale(X,S,-3) %<-- Same as above. +%% +Z = scale(X,Y,1:3) %<-- Scale by a sparse tensor. +%% +X .* Y %<-- Same as above. \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/S_test_problems_doc.m b/external/tensor_toolbox_2.5/doc/S_test_problems_doc.m new file mode 100755 index 0000000..14f3bbe --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/S_test_problems_doc.m @@ -0,0 +1,266 @@ +%% Creating test problems and initial guesses +% We demonstrate how to use Tensor Toolbox |create_problem| and +% |create_guess| functions to create test problems for fitting algorithms. + +%% Creating a CP test problem +% The |create_problem| function allows a user to generate a test problem +% with a known solution having a pre-specified solution. The +% |create_problem| function generates both the solution (as a |ktensor| for +% CP) and the test data (as a |tensor|). We later show that a +% pre-specificed solution can be used as well. + +% Create a problem +info = create_problem('Size', [5 4 3], 'Num_Factors', 3, 'Noise', 0.10); + +%% + +% Display the solution created by create_problem +soln = info.Soln + +%% + +% Display the data created by create_problem +data = info.Data + +%% + +% The difference between true solution and measured data should match the +% specified 10% noise. +diff = norm(full(info.Soln) - info.Data)/norm(full(info.Soln)) + +%% Creating a Tucker test problem +% The |create_problem| function can also be used to create Tucker problems +% by specifying the |'Type'| as |'Tucker'|. In this case, the +% |create_problem| function generates both the solution (as a |ttensor| for +% Tucker) and the test data (as a |tensor|). + +% Create a problem +info = create_problem('Type', 'Tucker', 'Size', [5 4 3], 'Num_Factors', [3 3 2]); + +%% + +% Display the Tucker-type solution created by create_problem +soln = info.Soln + +%% + +% Difference between true solution and measured data (default noise is 10%) +diff = norm(full(info.Soln) - info.Data)/norm(full(info.Soln)) + +%% Recreating the same test problem +% We can recreate exactly the same test problem when we use the same random +% seed and other parameters. + +% Set-up, including specifying random state +sz = [5 4 3]; %<- Size +nf = 2; %<- Number of components +state = RandStream.getDefaultStream.State; %<- Random state + +%% + +% Generate first test problem +info1 = create_problem('Size', sz, 'Num_Factors', nf, 'State', state); + +%% + +% Generate second identical test problem +info2 = create_problem('Size', sz, 'Num_Factors', nf, 'State', state); + +%% + +% Check that the solutions are identical +tf = isequal(info1.Soln, info2.Soln) + +%% + +% Check that the data are identical +diff = norm(info1.Data - info2.Data) + +%% Checking default parameters and recreating the same test problem +% The |create_problem| function returns the parameters that were used to +% generate it. These can be used to see the defaults. Additionally, if +% these are saved, they can be used to recreate the same test problems for +% future experiments. + +% Generate test problem and use second output argument for parameters. +[info1,params] = create_problem('Size', [5 4 3], 'Num_Factors', 2); + +%% + +% Here are the parameters +params + +%% + +% Recreate an identical test problem +info2 = create_problem(params); + +%% + +% Check that the solutions are identical +tf = isequal(info1.Soln, info2.Soln) + +%% + +% Check that the data are identical +diff = norm(info1.Data - info2.Data) + +%% Options for creating factor matrices, core tensors, and lambdas +% Any function with two arguments specifying the size can be used to +% generate the factor matrices. This is specified by the +% |'Factor_Generator'| option to |create_problem|. +% +% Pre-defined options for |'Factor_Generator'| for creating factor matrices +% (for CP or Tucker) include: +% +% * |'rand'| - Uniform on [0,1] +% * |'randn'| - Gaussian with mean 0 and std 1 +% * |'orthogonal'| - Generates a random orthogonal matrix. This option only +% works when the number of factors is less than or equal to the smallest +% dimension. +% * |'stochastic'| - Generates nonnegative factor matrices so that each +% column sums to one. +% +% Pre-defined options for |'Lambda_Generator'| for creating lambda vector +% (for CP) include: +% +% * |'rand'| - Uniform on [0,1] +% * |'randn'| - Gaussian with mean 0 and std 1 +% * |'orthogonal'| - Creates a random vector with norm one. +% * |'stochastic'| - Creates a random nonnegative vector whose entries sum +% to one. +% +% Pre-defined options for |'Core_Generator'| for creating core tensors (for +% Tucker) include: +% +% * |'rand'| - Uniform on [0,1] +% * |'randn'| - Gaussian with mean 0 and std 1 + +% Here is ane example of a custom factor generator +factor_generator = @(m,n) 100*rand(m,n); +info = create_problem('Size', [5 4 3], 'Num_Factors', 2, ... + 'Factor_Generator', factor_generator, 'Lambda_Generator', @ones); +first_factor_matrix = info.Soln.U{1} + +%% + +% Here is an example of a custom core generator for Tucker: +info = create_problem('Type', 'Tucker', 'Size', [5 4 3], ... + 'Num_Factors', [2 2 2], 'Core_Generator', @tenones); +core = info.Soln.core + +%% + +% Here's another example for CP, this time using a function to create +% factor matrices such that the inner products of the columns are +% prespecified. +info = create_problem('Size', [5 4 3], 'Num_Factors', 3, ... + 'Factor_Generator', @(m,n) tt_ccong(m,n,.9)); +U = info.Soln.U{1}; +congruences = U'*U + +%% Generating data from an existing solution +% It's possible to skip the solution generation altogether and instead just +% generate appropriate test data. + +% Manually generate a test problem (or it comes from some +% previous call to |create_problem|. +soln = ktensor({rand(50,3), rand(40,3), rand(30,3)}); + +% Use that soln to create new test problem. +info = create_problem('Soln', soln); + +% Check whether solutions is equivalent to the input +iseq = isequal(soln,info.Soln) + +%% Creating dense missing data problems +% It's possible to create problems that have a percentage of missing data. +% The problem generator randomly creates the pattern of missing data. + +% Specify 25% missing data as follows: +[info,params] = create_problem('Size', [5 4 3], 'M', 0.25); + +%% + +% Here is the pattern of known data (1 = known, 0 = unknown) +info.Pattern + +%% + +% Here is the data (incl. noise) with missing entries zeroed out +info.Data + +%% Creating sparse missing data problems. +% If |Sparse_M| is set to true, then the data returned +% is sparse. Moreover, the dense versions are never explicitly created. +% This option only works when M >= 0.8. + +% Specify 80% missing data and sparse +info = create_problem('Size', [5 4 3], 'M', 0.80, 'Sparse_M', true); + +%% + +% Here is the pattern of known data +info.Pattern + +%% + +% Here is the data (incl. noise) with missing entries zeroed out +info.Data + +%% Create missing data problems with a pre-specified pattern +% It's also possible to provide a specific pattern (dense or sparse) to be +% used to specify where data should be missing. + +% Create pattern +P = tenrand([5 4 3]) > 0.5; +% Create test problem with that pattern +info = create_problem('Size', size(P), 'M', P); +% Show the data +info.Data + +%% Creating sparse problems (CP only) +% If we assume each model parameter is the input to a Poisson process, then +% we can generate a sparse test problems. This requires that all the factor +% matrices and lambda be nonnegative. The default factor generator +% ('randn') won't work since it produces both positive and negative values. + +% Generate factor matrices with a few large entries in each column; this +% will be the basis of our soln. +sz = [20 15 10]; +nf = 4; +A = cell(3,1); +for n = 1:length(sz) + A{n} = rand(sz(n), nf); + for r = 1:nf + p = randperm(sz(n)); + idx = p(1:round(.2*sz(n))); + A{n}(idx,r) = 10 * A{n}(idx,r); + end +end +S = ktensor(A); +S = normalize(S,'sort',1); +%% + +% Create sparse test problem based on provided solution. The +% 'Sparse_Generation' says how many insertions to make based on the +% provided solution S. The lambda vector of the solution is automatically +% rescaled to match the number of insertions. +info = create_problem('Soln', S, 'Sparse_Generation', 500); +num_nonzeros = nnz(info.Data) +total_insertions = sum(info.Data.vals) +orig_lambda_vs_rescaled = S.lambda ./ info.Soln.lambda + +%% Generating an initial guess +% The |create_guess| function creates a random initial guess as a cell +% array of matrices. Its behavior is very similar to |create_problem|. A +% nice option is that you can generate an initial guess that is a +% pertubation of the solution. + +info = create_problem; + +% Create an initial guess to go with the problem that is just a 5% +% pertubation of the correct solution. +U = create_guess('Soln', info.Soln, 'Factor_Generator', 'pertubation', ... + 'Pertubation', 0.05); + diff --git a/external/tensor_toolbox_2.5/doc/T1_algorithms_doc.m b/external/tensor_toolbox_2.5/doc/T1_algorithms_doc.m new file mode 100755 index 0000000..931185d --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/T1_algorithms_doc.m @@ -0,0 +1,35 @@ +%% ALS optimization for CP and Tucker tensor decompositions + +%% Alternating least squares for PARAFAC/CANDECOMP +% The function |parafac_als| computes an estimate of the best rank-R +% PARAFAC model of a tensor X using an alternating least-squares +% algorithm. The input X can be a tensor, sptensor, ktensor, or +% ttensor. The result P is a ktensor. +rand('state',0); +X = sptenrand([5 4 3], 10) +%% +P = parafac_als(X,2) +%% +P = parafac_als(X,2,struct('dimorder',[3 2 1])) +%% +P = parafac_als(X,2,struct('dimorder',[3 2 1],'init','nvecs')) +%% +U0 = {rand(5,2),rand(4,2),[]}; %<-- Initial guess for factors of P +P = parafac_als(X,2,struct('dimorder',[3 2 1],'init',{U0})) +%% Alternating least squares for Tucker model +% The function |tucker_als| computes the best rank(R1,R2,..,Rn) +% approximation of tensor X, according to the specified dimensions in +% vector R. The input X can be a tensor, sptensor, ktensor, or +% ttensor. The result returned in T is a ttensor. +X = sptenrand([5 4 3], 10) +%% +T = tucker_als(X,2) %<-- best rank(2,2,2) approximation +%% +T = tucker_als(X,[2 2 1]) %<-- best rank(2,2,1) approximation +%% +T = tucker_als(X,2,struct('dimorder',[3 2 1])) +%% +T = tucker_als(X,2,struct('dimorder',[3 2 1],'init','eigs')) +%% +U0 = {rand(5,2),rand(4,2),[]}; %<-- Initial guess for factors of T +T = tucker_als(X,2,struct('dimorder',[3 2 1],'init',{U0})) diff --git a/external/tensor_toolbox_2.5/doc/T2_opt_algorithms_doc.m b/external/tensor_toolbox_2.5/doc/T2_opt_algorithms_doc.m new file mode 100755 index 0000000..b1da392 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/T2_opt_algorithms_doc.m @@ -0,0 +1,95 @@ +%% All-at-once optimization for CP tensor decomposition +% We explain how to use |cp_opt| with the POBLANO toolbox. + +%% Poblano Optimization Toolbox +% Check that you have Poblano 1.1 installed. The output of your 'ver' +% command should look something like the following. +ver + +%% Create an example problem. Here we have 10% noise. +R = 5; +info = create_problem('Size', [50 40 30], 'Num_Factors', R, 'Noise', 0.10); +X = info.Data; +M_true= info.Soln; + +%% Create initial guess using 'nvecs' +M_init = create_guess('Data', X, 'Num_Factors', R, ... + 'Factor_Generator', 'nvecs'); + + +%% Set up the optimization parameters +% It's genearlly a good idea to consider the parameters of the optimization +% method. The default options may be either too stringent or not stringent +% enough. The most important options to consider are detailed here. + +% Get the defaults +ncg_opts = ncg('defaults'); +% Tighten the stop tolerance (norm of gradient). This is often too large. +ncg_opts.StopTol = 1.0e-6; +% Tighten relative change in function value tolearnce. This is often too large. +ncg_opts.RelFuncTol = 1.0e-20; +% Increase the number of iterations. +ncg_opts.MaxIters = 10^4; +% Only display every 10th iteration +ncg_opts.DisplayIters = 10; +% Display the final set of options +ncg_opts + +%% Call the |cp_opt| method +% Here is an example call to the cp_opt method. By default, each iteration +% prints the least squares fit function value (being minimized) and the +% norm of the gradient. The meaning of any line search warnings +% can be checked via . +[M,~,output] = cp_opt(X, R, 'init', M_init, ... + 'alg', 'ncg', 'alg_options', ncg_opts); + +%% Check the output +% It's important to check the output of the optimization method. In +% particular, it's worthwhile to check the exit flag. +% A zero (0) indicates successful termination with the gradient smaller +% than the specified StopTol, and a three (3) indicates a successful +% termination where the change in function value is less than RelFuncTol. +% The meaning of any other flags can be checked via +% . +exitflag = output.ExitFlag + +%% +% The fit is the percentage of the data that is explained by the model. +% Because we have noise, we do not expect the fit to be perfect. +fit = output.Fit + +%% Evaluate the output +% We can "score" the similarity of the model computed by CP and compare +% that with the truth. The |score| function on ktensor's gives a score in +% [0,1] with 1 indicating a perfect match. Because we have noise, we do +% not expect the fit to be perfect. See for more details. +scr = score(M,M_true) + +%% Overfitting example +% Consider the case where we don't know R in advance. We might guess too +% high. Here we show a case where we guess R+1 factors rather than R. + +% Generate initial guess of the corret size +M_plus_init = create_guess('Data', X, 'Num_Factors', R+1, ... + 'Factor_Generator', 'nvecs'); + +%% + +% Loosen the stop tolerance (norm of gradient). +ncg_opts.StopTol = 1.0e-2; + +%% + +% Run the algorithm +[M_plus,~,output] = cp_opt(X, R+1, 'init', M_plus_init, ... + 'alg', 'ncg', 'alg_options', ncg_opts); +exitflag = output.ExitFlag +fit = output.Fit + + +%% + +% Check the answer (1 is perfect) +scr = score(M_plus, M_true) + diff --git a/external/tensor_toolbox_2.5/doc/T3_wopt_algorithms_doc.m b/external/tensor_toolbox_2.5/doc/T3_wopt_algorithms_doc.m new file mode 100755 index 0000000..a9bbf11 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/T3_wopt_algorithms_doc.m @@ -0,0 +1,121 @@ +%% Weighted optimization for CP tensor decomposition with incomplete data +% We explain how to use |cp_wopt| with the POBLANO toolbox. + +%% Create an example problem with missing data. +% Here we have 25% missing data and 10% noise. +R = 2; +info = create_problem('Size', [15 10 5], 'Num_Factors', R, ... + 'M', 0.25, 'Noise', 0.10); +X = info.Data; +P = info.Pattern; +M_true= info.Soln; + +%% Create initial guess using 'nvecs' +M_init = create_guess('Data', X, 'Num_Factors', R, ... + 'Factor_Generator', 'nvecs'); + + +%% Set up the optimization parameters +% It's genearlly a good idea to consider the parameters of the optimization +% method. The default options may be either too stringent or not stringent +% enough. The most important options to consider are detailed here. + +% Get the defaults +ncg_opts = ncg('defaults'); +% Tighten the stop tolerance (norm of gradient). This is often too large. +ncg_opts.StopTol = 1.0e-6; +% Tighten relative change in function value tolearnce. This is often too large. +ncg_opts.RelFuncTol = 1.0e-20; +% Increase the number of iterations. +ncg_opts.MaxIters = 10^4; +% Only display every 10th iteration +ncg_opts.DisplayIters = 10; +% Display the final set of options +ncg_opts + +%% Call the |cp_wopt| method +% Here is an example call to the cp_opt method. By default, each iteration +% prints the least squares fit function value (being minimized) and the +% norm of the gradient. The meaning of any line search warnings +% can be checked via . +[M,~,output] = cp_wopt(X, P, R, 'init', M_init, ... + 'alg', 'ncg', 'alg_options', ncg_opts); + +%% Check the output +% It's important to check the output of the optimization method. In +% particular, it's worthwhile to check the exit flag. +% A zero (0) indicates successful termination with the gradient smaller +% than the specified StopTol, and a three (3) indicates a successful +% termination where the change in function value is less than RelFuncTol. +% The meaning of any other flags can be checked via +% . +exitflag = output.ExitFlag + + +%% Evaluate the output +% We can "score" the similarity of the model computed by CP and compare +% that with the truth. The |score| function on ktensor's gives a score in +% [0,1] with 1 indicating a perfect match. Because we have noise, we do +% not expect the fit to be perfect. See for more details. +scr = score(M,M_true) + +%% Create a SPARSE example problem with missing data. +% Here we have 95% missing data and 10% noise. +R = 2; +info = create_problem('Size', [150 100 50], 'Num_Factors', R, ... + 'M', 0.95, 'Sparse_M', true, 'Noise', 0.10); +X = info.Data; +P = info.Pattern; +M_true= info.Soln; + +%% Create initial guess using 'nvecs' +M_init = create_guess('Data', X, 'Num_Factors', R, ... + 'Factor_Generator', 'nvecs'); + + +%% Set up the optimization parameters +% It's genearlly a good idea to consider the parameters of the optimization +% method. The default options may be either too stringent or not stringent +% enough. The most important options to consider are detailed here. + +% Get the defaults +ncg_opts = ncg('defaults'); +% Tighten the stop tolerance (norm of gradient). This is often too large. +ncg_opts.StopTol = 1.0e-6; +% Tighten relative change in function value tolearnce. This is often too large. +ncg_opts.RelFuncTol = 1.0e-20; +% Increase the number of iterations. +ncg_opts.MaxIters = 10^4; +% Only display every 10th iteration +ncg_opts.DisplayIters = 10; +% Display the final set of options +ncg_opts + +%% Call the |cp_wopt| method +% Here is an example call to the cp_opt method. By default, each iteration +% prints the least squares fit function value (being minimized) and the +% norm of the gradient. The meaning of any line search warnings +% can be checked via . +[M,~,output] = cp_wopt(X, P, R, 'init', M_init, ... + 'alg', 'ncg', 'alg_options', ncg_opts); + +%% Check the output +% It's important to check the output of the optimization method. In +% particular, it's worthwhile to check the exit flag. +% A zero (0) indicates successful termination with the gradient smaller +% than the specified StopTol, and a three (3) indicates a successful +% termination where the change in function value is less than RelFuncTol. +% The meaning of any other flags can be checked via +% . +exitflag = output.ExitFlag + + +%% Evaluate the output +% We can "score" the similarity of the model computed by CP and compare +% that with the truth. The |score| function on ktensor's gives a score in +% [0,1] with 1 indicating a perfect match. Because we have noise, we do +% not expect the fit to be perfect. See for more details. +scr = score(M,M_true) + diff --git a/external/tensor_toolbox_2.5/doc/T4_cpapr_doc.m b/external/tensor_toolbox_2.5/doc/T4_cpapr_doc.m new file mode 100755 index 0000000..5bad975 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/T4_cpapr_doc.m @@ -0,0 +1,41 @@ +%% Alternating Poisson Regression for fitting CP to sparse count data + +%% Set up a sample problem +% We follow the general procedure outlined by E. C. Chi and T. G. Kolda, +% On Tensors, Sparsity, and Nonnegative Factorizations, arXiv:1112.2414 +% [math.NA], December 2011 (http://arxiv.org/abs/1112.2414). + +% Pick the size and rank +sz = [100 80 60]; +R = 5; + +% Generate factor matrices with a few large entries in each column; this +% will be the basis of our soln. +A = cell(3,1); +for n = 1:length(sz) + A{n} = rand(sz(n), R); + for r = 1:R + p = randperm(sz(n)); + nbig = round( (1/R)*sz(n) ); + A{n}(p(1:nbig),r) = 100 * A{n}(p(1:nbig),r); + end +end +lambda = rand(R,1); +S = ktensor(lambda, A); +S = normalize(S,'sort',1); + +% Create sparse test problem based on provided solution. +nz = prod(sz) * .05; +info = create_problem('Soln', S, 'Sparse_Generation', nz); + +% Extract data and solution +X = info.Data; +M_true = info.Soln; + +%% Call CP-APR + +% Compute a solution +M = cp_apr(X, R, 'printitn', 10); + +% Score the solution +factor_match_score = score(M, M_true, 'greedy', true) diff --git a/external/tensor_toolbox_2.5/doc/V_SSHOPM_doc.m b/external/tensor_toolbox_2.5/doc/V_SSHOPM_doc.m new file mode 100755 index 0000000..b0a13c3 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/V_SSHOPM_doc.m @@ -0,0 +1,32 @@ +%% Shifted Symmetric Higher-Order Power Method (SSHOPM) + +%% Data tensor +% From Example 1 in E. Kofidis and P. A. Regalia, On the best rank-1 +% approximation of higher-order supersymmetric tensors, SIAM J. Matrix +% Anal. Appl., 23 (2002), pp. 863–884, DOI: 10.1137/S0895479801387413. +A = tenzeros([3 3 3 3]); +A(perms([1 1 1 1])) = 0.2883; +A(perms([1 1 1 2])) = -0.0031; +A(perms([1 1 1 3])) = 0.1973; +A(perms([1 1 2 2])) = -0.2485; +A(perms([1 1 2 3])) = -0.2939; +A(perms([1 1 3 3])) = 0.3847; +A(perms([1 2 2 2])) = 0.2972; +A(perms([1 2 2 3])) = 0.1862; +A(perms([1 2 3 3])) = 0.0919; +A(perms([1 3 3 3])) = -0.3619; +A(perms([2 2 2 2])) = 0.1241; +A(perms([2 2 2 3])) = -0.3420; +A(perms([2 2 3 3])) = 0.2127; +A(perms([2 3 3 3])) = 0.2727; +A(perms([3 3 3 3])) = -0.3054; + +%% Call SSHOPM with no shift +% The method with no shift will fail to converge. +[lambda, x, flag, it, ~, trace] = sshopm(A, 'MaxIts', 100); +plot(0:it, trace(1:it+1),'b.-'); + +%% Call SSHOPM with shift + +[lambda, x, flag, it, ~, trace] = sshopm(A, 'MaxIts', 100, 'Shift', 1); +plot(0:it, trace(1:it+1),'b.-'); diff --git a/external/tensor_toolbox_2.5/doc/html/A1_tensor_doc.html b/external/tensor_toolbox_2.5/doc/html/A1_tensor_doc.html new file mode 100755 index 0000000..c16b991 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/A1_tensor_doc.html @@ -0,0 +1,908 @@ + + + + + Tensors

Tensors

Tensors are extensions of multidimensional arrays with additional operations defined on them. Here we explain the basics of creating and working with tensors.

Contents

Creating a tensor from an array

The tensor command converts a (multidimensional) array to a tensor object.

M = ones(4,3,2); %<-- A 4 x 3 x 2 array.
+X = tensor(M) %<-- Convert to a tensor object.
+
X is a tensor of size 4 x 3 x 2
+	X(:,:,1) = 
+	     1     1     1
+	     1     1     1
+	     1     1     1
+	     1     1     1
+	X(:,:,2) = 
+	     1     1     1
+	     1     1     1
+	     1     1     1
+	     1     1     1
+

Optionally, you can specify a different shape for the tensor, so long as the input array has the right number of elements.

X = tensor(M,[2 3 4]) %<-- M has 24 elements.
+
X is a tensor of size 2 x 3 x 4
+	X(:,:,1) = 
+	     1     1     1
+	     1     1     1
+	X(:,:,2) = 
+	     1     1     1
+	     1     1     1
+	X(:,:,3) = 
+	     1     1     1
+	     1     1     1
+	X(:,:,4) = 
+	     1     1     1
+	     1     1     1
+

Creating a one-dimensional tensor

The tensor class explicitly supports order-one tensors as well as trailing singleton dimensions, but the size must be explicit in the constructor. By default, a column array produces a 2-way tensor.

X = tensor(rand(5,1)) %<-- Creates a 2-way tensor.
+
X is a tensor of size 5 x 1
+	X(:,:) = 
+	    0.6795
+	    0.3197
+	    0.7152
+	    0.8638
+	    0.4895
+

This is fixed by specifying the size explicitly.

X = tensor(rand(5,1),5) %<-- Creates a 1-way tensor.
+
X is a tensor of size 5
+	X(:) = 
+	    0.0502
+	    0.2407
+	    0.1686
+	    0.0732
+	    0.5436
+

Specifying trailing singleton dimensions in a tensor

Likewise, trailing singleton dimensions must be explictly specified.

Y = tensor(rand(4,3,1)) %<-- Creates a 2-way tensor.
+
Y is a tensor of size 4 x 3
+	Y(:,:) = 
+	    0.5950    0.9950    0.4463
+	    0.8758    0.8257    0.2808
+	    0.9607    0.5871    0.7426
+	    0.2159    0.8791    0.6860
+
Y = tensor(rand(4,3,1),[4 3 1]) %<-- Creates a 3-way tensor.
+
Y is a tensor of size 4 x 3 x 1
+	Y(:,:,1) = 
+	    0.3848    0.2489    0.6783
+	    0.9311    0.1993    0.6748
+	    0.2942    0.7841    0.6606
+	    0.9406    0.7502    0.5375
+

Unfortunately, the whos command does not report the size of 1D objects correctly (last checked for MATLAB 2006a).

whos X Y %<-- Doesn't report the right size for X!
+
  Name      Size             Bytes  Class     Attributes
+
+  X         1x1                400  tensor              
+  Y         4x3x1              472  tensor              
+
+

The constituent parts of a tensor

X = tenrand([4 3 2]); %<-- Create data.
+X.data %<-- The array.
+
+ans(:,:,1) =
+
+    0.2938    0.3392    0.8987
+    0.5341    0.7094    0.0823
+    0.4857    0.4997    0.1435
+    0.8561    0.0811    0.1588
+
+
+ans(:,:,2) =
+
+    0.6249    0.6685    0.6517
+    0.6480    0.4876    0.5358
+    0.9163    0.8645    0.1728
+    0.6481    0.6103    0.3503
+
+
X.size %<-- The size.
+
+ans =
+
+     4     3     2
+
+

Creating a tensor from its constituent parts

Y = tensor(X.data,X.size) %<-- Copies X.
+
Y is a tensor of size 4 x 3 x 2
+	Y(:,:,1) = 
+	    0.2938    0.3392    0.8987
+	    0.5341    0.7094    0.0823
+	    0.4857    0.4997    0.1435
+	    0.8561    0.0811    0.1588
+	Y(:,:,2) = 
+	    0.6249    0.6685    0.6517
+	    0.6480    0.4876    0.5358
+	    0.9163    0.8645    0.1728
+	    0.6481    0.6103    0.3503
+

Creating an empty tensor

An empty constructor exists, primarily to support loading previously saved data in MAT-files.

X = tensor %<-- Creates an empty tensor.
+
X is a tensor of size [empty tensor]
+	X = []
+

Use tenone to create a tensor of all ones

X = tenones([3 4 2]) %<-- Creates a 3 x 4 x 2 tensor of ones.
+
X is a tensor of size 3 x 4 x 2
+	X(:,:,1) = 
+	     1     1     1     1
+	     1     1     1     1
+	     1     1     1     1
+	X(:,:,2) = 
+	     1     1     1     1
+	     1     1     1     1
+	     1     1     1     1
+

Use tenzeros to create a tensor of all zeros

X = tenzeros([1 4 2]) %<-- Creates a 1 x 4 x 2 tensor of zeros.
+
X is a tensor of size 1 x 4 x 2
+	X(:,:,1) = 
+	     0     0     0     0
+	X(:,:,2) = 
+	     0     0     0     0
+

Use tenrand to create a random tensor

X = tenrand([5 4 2]) %<-- Creates a random 5 x 4 x 2 tensor.
+
X is a tensor of size 5 x 4 x 2
+	X(:,:,1) = 
+	    0.0427    0.5465    0.0834    0.3193
+	    0.0597    0.7262    0.7344    0.0307
+	    0.1797    0.9139    0.7407    0.1558
+	    0.1281    0.0322    0.9950    0.4587
+	    0.6957    0.2254    0.0754    0.0957
+	X(:,:,2) = 
+	    0.9420    0.6775    0.1161    0.1220
+	    0.4345    0.6444    0.2411    0.2275
+	    0.3170    0.4114    0.5672    0.6620
+	    0.1854    0.6616    0.9413    0.5693
+	    0.4431    0.9012    0.6916    0.4649
+

Use squeeze to remove singleton dimensions from a tensor

squeeze(Y) %<-- Removes singleton dimensions.
+
ans is a tensor of size 4 x 3 x 2
+	ans(:,:,1) = 
+	    0.2938    0.3392    0.8987
+	    0.5341    0.7094    0.0823
+	    0.4857    0.4997    0.1435
+	    0.8561    0.0811    0.1588
+	ans(:,:,2) = 
+	    0.6249    0.6685    0.6517
+	    0.6480    0.4876    0.5358
+	    0.9163    0.8645    0.1728
+	    0.6481    0.6103    0.3503
+

Use double to convert a tensor to a (multidimensional) array

double(Y) %<-- Converts Y to a standard MATLAB array.
+
+ans(:,:,1) =
+
+    0.2938    0.3392    0.8987
+    0.5341    0.7094    0.0823
+    0.4857    0.4997    0.1435
+    0.8561    0.0811    0.1588
+
+
+ans(:,:,2) =
+
+    0.6249    0.6685    0.6517
+    0.6480    0.4876    0.5358
+    0.9163    0.8645    0.1728
+    0.6481    0.6103    0.3503
+
+
Y.data %<-- Same thing.
+
+ans(:,:,1) =
+
+    0.2938    0.3392    0.8987
+    0.5341    0.7094    0.0823
+    0.4857    0.4997    0.1435
+    0.8561    0.0811    0.1588
+
+
+ans(:,:,2) =
+
+    0.6249    0.6685    0.6517
+    0.6480    0.4876    0.5358
+    0.9163    0.8645    0.1728
+    0.6481    0.6103    0.3503
+
+

Use ndims and size to get the size of a tensor

ndims(Y) %<-- Number of dimensions (or ways).
+
+ans =
+
+     3
+
+
size(Y) %<-- Row vector with the sizes of all dimension.
+
+ans =
+
+     4     3     2
+
+
size(Y,3) %<-- Size of a single dimension.
+
+ans =
+
+     2
+
+

Subscripted reference for a tensor

X = tenrand([3 4 2 1]); %<-- Create a 3 x 4 x 2 x 1 random tensor.
+X(1,1,1,1) %<-- Extract a single element.
+
+ans =
+
+    0.0870
+
+

It is possible to extract a subtensor that contains a single element. Observe that singleton dimensions are not dropped unless they are specifically specified, e.g., as above.

X(1,1,1,:) %<-- Produces a tensor of order 1 and size 1.
+
ans is a tensor of size 1
+	ans(:) = 
+	    0.0870
+

In general, specified dimensions are dropped from the result. Here we specify the second and third dimension.

X(:,1,1,:) %<-- Produces a tensor of size 3 x 1.
+
ans is a tensor of size 3 x 1
+	ans(:,:) = 
+	    0.0870
+	    0.7143
+	    0.8403
+

Moreover, the subtensor is automatically renumbered/resized in the same way that MATLAB works for arrays except that singleton dimensions are handled explicitly.

X(1:2,[2 4],1,:) %<-- Produces a tensor of size 2 x 2 x 1.
+
ans is a tensor of size 2 x 2 x 1
+	ans(:,:,1) = 
+	    0.1285    0.4259
+	    0.6423    0.7998
+

It's also possible to extract a list of elements by passing in an array of subscripts or a column array of linear indices.

subs = [1,1,1,1; 3,4,2,1]; X(subs) %<-- Extract 2 values by subscript.
+
+ans =
+
+    0.0870
+    0.5047
+
+
inds = [1; 24]; X(inds) %<-- Same thing with linear indices.
+
+ans =
+
+    0.0870
+    0.5047
+
+

The difference between extracting a subtensor and a list of linear indices is ambiguous for 1-dimensional tensors. We can specify 'extract' as a second argument whenever we are using a list of subscripts.

X = tenrand(10); %<-- Create a random tensor.
+X([1:6]') %<-- Extract a subtensor.
+
ans is a tensor of size 6
+	ans(:) = 
+	    0.7649
+	    0.2766
+	    0.2007
+	    0.0794
+	    0.8773
+	    0.4142
+
X([1:6]','extract') %<-- Same thing *but* result is a vector.
+
+ans =
+
+    0.7649
+    0.2766
+    0.2007
+    0.0794
+    0.8773
+    0.4142
+
+

Subscripted assignment for a tensor

We can assign a single element, an entire subtensor, or a list of values for a tensor.

X = tenrand([3,4,2]); %<-- Create some data.
+X(1,1,1) = 0 %<-- Replaces the (1,1,1) element.
+
X is a tensor of size 3 x 4 x 2
+	X(:,:,1) = 
+	         0    0.8826    0.5630    0.5628
+	    0.5350    0.3528    0.5722    0.0352
+	    0.2881    0.7953    0.0467    0.9053
+	X(:,:,2) = 
+	    0.9564    0.0386    0.1828    0.5359
+	    0.6141    0.5282    0.2898    0.5675
+	    0.7694    0.6553    0.7550    0.4955
+
X(1:2,1:2,1) = ones(2,2) %<-- Replaces a 2 x 2 subtensor.
+
X is a tensor of size 3 x 4 x 2
+	X(:,:,1) = 
+	    1.0000    1.0000    0.5630    0.5628
+	    1.0000    1.0000    0.5722    0.0352
+	    0.2881    0.7953    0.0467    0.9053
+	X(:,:,2) = 
+	    0.9564    0.0386    0.1828    0.5359
+	    0.6141    0.5282    0.2898    0.5675
+	    0.7694    0.6553    0.7550    0.4955
+
X([1 1 1;1 1 2]) = [5;7] %<-- Replaces the (1,1,1) and (1,1,2) elements.
+
X is a tensor of size 3 x 4 x 2
+	X(:,:,1) = 
+	    5.0000    1.0000    0.5630    0.5628
+	    1.0000    1.0000    0.5722    0.0352
+	    0.2881    0.7953    0.0467    0.9053
+	X(:,:,2) = 
+	    7.0000    0.0386    0.1828    0.5359
+	    0.6141    0.5282    0.2898    0.5675
+	    0.7694    0.6553    0.7550    0.4955
+
X([1;13]) = [5;7] %<-- Same as above using linear indices.
+
X is a tensor of size 3 x 4 x 2
+	X(:,:,1) = 
+	    5.0000    1.0000    0.5630    0.5628
+	    1.0000    1.0000    0.5722    0.0352
+	    0.2881    0.7953    0.0467    0.9053
+	X(:,:,2) = 
+	    7.0000    0.0386    0.1828    0.5359
+	    0.6141    0.5282    0.2898    0.5675
+	    0.7694    0.6553    0.7550    0.4955
+

It is possible to grow the tensor automatically by assigning elements outside the original range of the tensor.

X(1,1,3) = 1 %<-- Grows the size of the tensor.
+
X is a tensor of size 3 x 4 x 3
+	X(:,:,1) = 
+	    5.0000    1.0000    0.5630    0.5628
+	    1.0000    1.0000    0.5722    0.0352
+	    0.2881    0.7953    0.0467    0.9053
+	X(:,:,2) = 
+	    7.0000    0.0386    0.1828    0.5359
+	    0.6141    0.5282    0.2898    0.5675
+	    0.7694    0.6553    0.7550    0.4955
+	X(:,:,3) = 
+	     1     0     0     0
+	     0     0     0     0
+	     0     0     0     0
+

Using end for the last array index.

X(end,end,end)  %<-- Same as X(3,4,3).
+
+ans =
+
+     0
+
+
X(1,1,1:end-1)  %<-- Same as X(1,1,1:2).
+
ans is a tensor of size 2
+	ans(:) = 
+	     5
+	     7
+

It is also possible to use end to index past the end of an array.

X(1,1,end+1) = 5 %<-- Same as X(1,1,4).
+
X is a tensor of size 3 x 4 x 4
+	X(:,:,1) = 
+	    5.0000    1.0000    0.5630    0.5628
+	    1.0000    1.0000    0.5722    0.0352
+	    0.2881    0.7953    0.0467    0.9053
+	X(:,:,2) = 
+	    7.0000    0.0386    0.1828    0.5359
+	    0.6141    0.5282    0.2898    0.5675
+	    0.7694    0.6553    0.7550    0.4955
+	X(:,:,3) = 
+	     1     0     0     0
+	     0     0     0     0
+	     0     0     0     0
+	X(:,:,4) = 
+	     5     0     0     0
+	     0     0     0     0
+	     0     0     0     0
+

Use find for subscripts of nonzero elements of a tensor

The find function returns a list of nonzero subscripts for a tensor. Note that differs from the standard version, which returns linear indices.

X = tensor(floor(3*rand(2,2,2))) %<-- Generate some data.
+
X is a tensor of size 2 x 2 x 2
+	X(:,:,1) = 
+	     1     2
+	     1     2
+	X(:,:,2) = 
+	     1     2
+	     1     0
+
[S,V] = find(X) %<-- Find all the nonzero subscripts and values.
+
+S =
+
+     1     1     1
+     2     1     1
+     1     2     1
+     2     2     1
+     1     1     2
+     2     1     2
+     1     2     2
+
+
+V =
+
+     1
+     1
+     2
+     2
+     1
+     1
+     2
+
+
S = find(X >= 2) %<-- Find subscripts of values >= 2.
+
+S =
+
+     1     2     1
+     2     2     1
+     1     2     2
+
+
V = X(S) %<-- Extract the corresponding values from X.
+
+V =
+
+     2
+     2
+     2
+
+

Basic operations (plus, minus, and, or, etc.) on a tensor

The tensor object supports many basic operations, illustrated here.

A = tensor(floor(3*rand(2,3,2)))
+B = tensor(floor(3*rand(2,3,2)))
+
A is a tensor of size 2 x 3 x 2
+	A(:,:,1) = 
+	     0     0     2
+	     0     0     1
+	A(:,:,2) = 
+	     0     1     1
+	     2     2     1
+B is a tensor of size 2 x 3 x 2
+	B(:,:,1) = 
+	     0     2     2
+	     2     1     2
+	B(:,:,2) = 
+	     2     0     2
+	     1     2     2
+
A & B %<-- Calls and.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     0     1
+	     0     0     1
+	ans(:,:,2) = 
+	     0     0     1
+	     1     1     1
+
A | B %<-- Calls or.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     1     1
+	     1     1     1
+	ans(:,:,2) = 
+	     1     1     1
+	     1     1     1
+
xor(A,B) %<-- Calls xor.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     1     0
+	     1     1     0
+	ans(:,:,2) = 
+	     1     1     0
+	     0     0     0
+
A==B %<-- Calls eq.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     1     0     1
+	     0     0     0
+	ans(:,:,2) = 
+	     0     0     0
+	     0     1     0
+
A~=B %<-- Calls neq.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     1     0
+	     1     1     1
+	ans(:,:,2) = 
+	     1     1     1
+	     1     0     1
+
A>B %<-- Calls gt.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     0     0
+	     0     0     0
+	ans(:,:,2) = 
+	     0     1     0
+	     1     0     0
+
A>=B %<-- Calls ge.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     1     0     1
+	     0     0     0
+	ans(:,:,2) = 
+	     0     1     0
+	     1     1     0
+
A<B %<-- Calls lt.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     1     0
+	     1     1     1
+	ans(:,:,2) = 
+	     1     0     1
+	     0     0     1
+
A<=B %<-- Calls le.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     1     1     1
+	     1     1     1
+	ans(:,:,2) = 
+	     1     0     1
+	     0     1     1
+
~A %<-- Calls not.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     1     1     0
+	     1     1     0
+	ans(:,:,2) = 
+	     1     0     0
+	     0     0     0
+
+A %<-- Calls uplus.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     0     2
+	     0     0     1
+	ans(:,:,2) = 
+	     0     1     1
+	     2     2     1
+
-A %<-- Calls uminus.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     0    -2
+	     0     0    -1
+	ans(:,:,2) = 
+	     0    -1    -1
+	    -2    -2    -1
+
A+B %<-- Calls plus.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     2     4
+	     2     1     3
+	ans(:,:,2) = 
+	     2     1     3
+	     3     4     3
+
A-B %<-- Calls minus.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0    -2     0
+	    -2    -1    -1
+	ans(:,:,2) = 
+	    -2     1    -1
+	     1     0    -1
+
A.*B %<-- Calls times.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     0     4
+	     0     0     2
+	ans(:,:,2) = 
+	     0     0     2
+	     2     4     2
+
5*A %<-- Calls mtimes.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     0    10
+	     0     0     5
+	ans(:,:,2) = 
+	     0     5     5
+	    10    10     5
+
A.^B %<-- Calls power.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     1     0     4
+	     0     0     1
+	ans(:,:,2) = 
+	     0     1     1
+	     2     4     1
+
A.^2 %<-- Calls power.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     0     4
+	     0     0     1
+	ans(:,:,2) = 
+	     0     1     1
+	     4     4     1
+
A.\B %<-- Calls ldivide.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	   NaN   Inf     1
+	   Inf   Inf     2
+	ans(:,:,2) = 
+	       Inf         0    2.0000
+	    0.5000    1.0000    2.0000
+
A./2 %<-- Calls rdivide.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	         0         0    1.0000
+	         0         0    0.5000
+	ans(:,:,2) = 
+	         0    0.5000    0.5000
+	    1.0000    1.0000    0.5000
+
A./B %<-- Calls rdivide (but beware divides by zero!)
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	       NaN         0    1.0000
+	         0         0    0.5000
+	ans(:,:,2) = 
+	         0       Inf    0.5000
+	    2.0000    1.0000    0.5000
+

Using tenfun for elementwise operations on one or more tensors

The function tenfun applies a specified function to a number of tensors. This can be used for any function that is not predefined for tensors.

tenfun(@(x)(x+1),A) %<-- Increment every element of A by one.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     1     1     3
+	     1     1     2
+	ans(:,:,2) = 
+	     1     2     2
+	     3     3     2
+
tenfun(@max,A,B) %<-- Max of A and B, elementwise.
+
ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     2     2
+	     2     1     2
+	ans(:,:,2) = 
+	     2     1     2
+	     2     2     2
+
C = tensor(floor(5*rand(2,3,2))) %<-- Create another tensor.
+tenfun(@median,A,B,C) %<-- Elementwise means for A, B, and C.
+
C is a tensor of size 2 x 3 x 2
+	C(:,:,1) = 
+	     2     1     4
+	     1     1     1
+	C(:,:,2) = 
+	     4     2     3
+	     4     2     0
+ans is a tensor of size 2 x 3 x 2
+	ans(:,:,1) = 
+	     0     1     2
+	     1     1     1
+	ans(:,:,2) = 
+	     2     1     2
+	     2     2     1
+

Use permute to reorder the modes of a tensor

X = tensor(1:24,[3 4 2]) %<-- Create a tensor.
+
X is a tensor of size 3 x 4 x 2
+	X(:,:,1) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	X(:,:,2) = 
+	    13    16    19    22
+	    14    17    20    23
+	    15    18    21    24
+
permute(X,[3 2 1]) %<-- Reverse the modes.
+
ans is a tensor of size 2 x 4 x 3
+	ans(:,:,1) = 
+	     1     4     7    10
+	    13    16    19    22
+	ans(:,:,2) = 
+	     2     5     8    11
+	    14    17    20    23
+	ans(:,:,3) = 
+	     3     6     9    12
+	    15    18    21    24
+

Permuting a 1-dimensional tensor works correctly.

X = tensor(1:4,4); %<-- Create a 1-way tensor.
+permute(X,1) %<-- Call permute with *only* one dimension.
+
ans is a tensor of size 4
+	ans(:) = 
+	     1
+	     2
+	     3
+	     4
+

Displaying a tensor

The function disp can be used to display a tensor and correctly displays very small and large elements.

X = tensor(1:24,[3 4 2]); %<-- Create a 3 x 4 x 2 tensor.
+X(:,:,1) = X(:,:,1) * 1e15; %<-- Make the first slice very large.
+X(:,:,2) = X(:,:,2) * 1e-15; %<-- Make the second slice very small.
+disp(X)
+
ans is a tensor of size 3 x 4 x 2
+	ans(:,:,1) = 
+	  1.0e+016 *
+	    0.1000    0.4000    0.7000    1.0000
+	    0.2000    0.5000    0.8000    1.1000
+	    0.3000    0.6000    0.9000    1.2000
+	ans(:,:,2) = 
+	  1.0e-013 *
+	    0.1300    0.1600    0.1900    0.2200
+	    0.1400    0.1700    0.2000    0.2300
+	    0.1500    0.1800    0.2100    0.2400
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/A2_sptensor_doc.html b/external/tensor_toolbox_2.5/doc/html/A2_sptensor_doc.html new file mode 100755 index 0000000..f004a01 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/A2_sptensor_doc.html @@ -0,0 +1,753 @@ + + + + + Sparse Tensors

Sparse Tensors

MATLAB has no native ability to store sparse multidimensional arrays, only sparse matrices. Moreover, the compressed sparse column storage format for MATLAB sparse matrices is not readily adaptable to sparse tensors. Instead, the sptensor class stores the data in coordinate format.

Contents

Creating a sptensor

A sparse tensor can be created by passing in a list of subscripts and values. For example, here we pass in three subscripts and a scalar value. The resuling sparse tensor has three nonzero entries, and the size is the size of the largest subscript in each dimension.

rand('state',0); %<-- Setup for the script
+subs = [1,1,1;1,2,1;3,4,2]; %<-- Subscripts of the nonzeros.
+vals = [1; 2; 3]; %<-- The values of the nonzeros.
+X = sptensor(subs,vals) %<-- Create a sparse tensor with 3 nonzeros.
+
X is a sparse tensor of size 3 x 4 x 2 with 3 nonzeros
+	(1,1,1)     1
+	(1,2,1)     2
+	(3,4,2)     3
+
X = sptensor(subs,vals,[3 5 2]) %<-- Or, specify the size explicitly.
+
X is a sparse tensor of size 3 x 5 x 2 with 3 nonzeros
+	(1,1,1)     1
+	(1,2,1)     2
+	(3,4,2)     3
+

Values corresponding to repeated subscripts are summed. Also note that we can use a scalar as the second argument.

subs = [1 1 1; 1 1 3; 2 2 2; 4 4 4; 1 1 1; 1 1 1]; %<-- (1,1,1) is repeated.
+X = sptensor(subs,2) %<-- Equivalent to X = sptensor(subs,2*ones(6,1)).
+
X is a sparse tensor of size 4 x 4 x 4 with 4 nonzeros
+	(1,1,1)     6
+	(1,1,3)     2
+	(2,2,2)     2
+	(4,4,4)     2
+

Specifying the accumulation method for the constructor

By default, values corresponding to repeated elements are summed. However, it is possible to specify other actions to be taken.

X = sptensor(subs,2*ones(6,1),[4 4 4],@max) %<-- Maximum element.
+
X is a sparse tensor of size 4 x 4 x 4 with 4 nonzeros
+	(1,1,1)     2
+	(1,1,3)     2
+	(2,2,2)     2
+	(4,4,4)     2
+
myfun = @(x) sum(x) / 3; %<-- Total sum divided by three.
+X = sptensor(subs,2*ones(6,1),[4 4 4],myfun) %<-- Custom accumulation function.
+
X is a sparse tensor of size 4 x 4 x 4 with 4 nonzeros
+	(1,1,1)    2.0000
+	(1,1,3)    0.6667
+	(2,2,2)    0.6667
+	(4,4,4)    0.6667
+

Creating a one-dimensional sptensor.

X = sptensor([1;3;5],1,10) %<-- Same as X = sptensor([1;3;5],[1;1;1],1,10).
+
X is a sparse tensor of size 10 with 3 nonzeros
+	(1)     1
+	(3)     1
+	(5)     1
+
X = sptenrand(50,5) %<-- A random, sparse, order-1 tensor with 5 nonzeros.
+
X is a sparse tensor of size 50 with 5 nonzeros
+	(12)    0.7621
+	(25)    0.4565
+	(31)    0.0185
+	(45)    0.8214
+	(48)    0.4447
+

Creating an all-zero sptensor

X = sptensor([],[],[10 10 10]) %<-- Creates an all-zero tensor.
+
X is an all-zero sparse tensor of size 10 x 10 x 10
+
X = sptensor([10 10 10]) %<-- Same as above.
+
X is an all-zero sparse tensor of size 10 x 10 x 10
+

Constituent parts of a sptensor

X = sptenrand([40 30 20],5); %<-- Create data.
+X.subs %<-- Subscripts of nonzeros.
+
+ans =
+
+     8    27     3
+    25    13     2
+    30    13     1
+    32    29     8
+    37    28    17
+
+
X.vals %<-- Corresponding nonzero values.
+
+ans =
+
+    0.2028
+    0.1987
+    0.6038
+    0.2722
+    0.1988
+
+
X.size %<-- The size.
+
+ans =
+
+    40    30    20
+
+

Creating a sparse tensor from its constituent parts

Y = sptensor(X.subs,X.vals,X.size) %<-- Copies X.
+
Y is a sparse tensor of size 40 x 30 x 20 with 5 nonzeros
+	( 8,27, 3)    0.2028
+	(25,13, 2)    0.1987
+	(30,13, 1)    0.6038
+	(32,29, 8)    0.2722
+	(37,28,17)    0.1988
+

Creating an empty sptensor

An empty constructor exists, primarily to support loads of previously saved data.

Y = sptensor %<-- Create an empty sptensor.
+
Y is an all-zero sparse tensor of size [empty tensor]
+

Use sptenrand to create a random sptensor

X = sptenrand([10 10 10],0.01) %<-- Create a tensor with 1% nonzeroes.
+
X is a sparse tensor of size 10 x 10 x 10 with 10 nonzeros
+	( 1,9,2)    0.4966
+	( 3,4,9)    0.8998
+	( 5,6,7)    0.8216
+	( 5,7,4)    0.6449
+	( 5,9,2)    0.8180
+	( 6,5,9)    0.6602
+	( 7,2,6)    0.3420
+	( 8,1,7)    0.2897
+	( 9,8,4)    0.3412
+	(10,4,6)    0.5341
+

It is also posible to specify the precise number of nonzeros rather than a percentage.

X = sptenrand([10 10 10],10) %<-- Create a tensor with 10 nonzeros.
+
X is a sparse tensor of size 10 x 10 x 10 with 10 nonzeros
+	(4, 2, 3)    0.5828
+	(4,10, 1)    0.4235
+	(5, 3, 5)    0.5155
+	(6, 3, 3)    0.3340
+	(6, 9, 2)    0.4329
+	(7, 8,10)    0.2259
+	(7, 9, 1)    0.5798
+	(8, 8, 2)    0.7604
+	(8,10, 7)    0.5298
+	(9, 6, 9)    0.6405
+

Use squeeze to remove singleton dimensions from a sptensor

Y = sptensor([1 1 1; 2 1 1], 1, [2 1 1]) %<-- Create a sparse tensor.
+squeeze(Y) %<-- Remove singleton dimensions.
+
Y is a sparse tensor of size 2 x 1 x 1 with 2 nonzeros
+	(1,1,1)     1
+	(2,1,1)     1
+ans is a sparse tensor of size 2 with 2 nonzeros
+	(1)     1
+	(2)     1
+

Use full or tensor to convert a sptensor to a (dense) tensor

X = sptensor([1 1 1; 2 2 2], [1; 1]); %<-- Create a sparse tensor.
+Y = full(X) %<-- Convert it to a (dense) tensor.
+
Y is a tensor of size 2 x 2 x 2
+	Y(:,:,1) = 
+	     1     0
+	     0     0
+	Y(:,:,2) = 
+	     0     0
+	     0     1
+
Y = tensor(X) %<-- Same as above.
+
Y is a tensor of size 2 x 2 x 2
+	Y(:,:,1) = 
+	     1     0
+	     0     0
+	Y(:,:,2) = 
+	     0     0
+	     0     1
+

Use sptensor to convert a (dense) tensor to a sptensor

Z = sptensor(Y) %<-- Convert a tensor to a sptensor.
+
Z is a sparse tensor of size 2 x 2 x 2 with 2 nonzeros
+	(1,1,1)     1
+	(2,2,2)     1
+

Use double to convert a sptensor to a (dense) multidimensional array

Y = double(X) %<-- Creates a MATLAB array.
+
+Y(:,:,1) =
+
+     1     0
+     0     0
+
+
+Y(:,:,2) =
+
+     0     0
+     0     1
+
+

Use find to extract nonzeros from a tensor and then create a sptensor

The find command can be used to extract specific elements and then convert those into a sptensor.

X = tensor(rand(5,4,2),[5 4 2]) %<-- Create a tensor.
+S = find(X > 0.9) %<-- Extract subscipts of values greater than 0.9.
+V = X(S) %<-- Extract the corresponding values.
+Y = sptensor(S,V,[5 4 2]) %<-- Create a new tensor.
+
X is a tensor of size 5 x 4 x 2
+	X(:,:,1) = 
+	    0.2091    0.5678    0.4154    0.9708
+	    0.3798    0.7942    0.3050    0.9901
+	    0.7833    0.0592    0.8744    0.7889
+	    0.6808    0.6029    0.0150    0.4387
+	    0.4611    0.0503    0.7680    0.4983
+	X(:,:,2) = 
+	    0.2140    0.4120    0.6833    0.2071
+	    0.6435    0.7446    0.2126    0.6072
+	    0.3200    0.2679    0.8392    0.6299
+	    0.9601    0.4399    0.6288    0.3705
+	    0.7266    0.9334    0.1338    0.5751
+
+S =
+
+     1     4     1
+     2     4     1
+     4     1     2
+     5     2     2
+
+
+V =
+
+    0.9708
+    0.9901
+    0.9601
+    0.9334
+
+Y is a sparse tensor of size 5 x 4 x 2 with 4 nonzeros
+	(1,4,1)    0.9708
+	(2,4,1)    0.9901
+	(4,1,2)    0.9601
+	(5,2,2)    0.9334
+

Use ndims and size to get the size of a sptensor

ndims(Y) %<-- Number of dimensions or modes.
+
+ans =
+
+     3
+
+
size(Y) %<-- Size of Y.
+
+ans =
+
+     5     4     2
+
+
size(Y,3) %<-- Size of mode 3 of Y.
+
+ans =
+
+     2
+
+

Use nnz to get the number of nonzeros of a sptensor

nnz(Y) %<-- Number of nonzeros in Y.
+
+ans =
+
+     4
+
+

Subscripted reference for a sptensor

X = sptensor([4,4,4;2,2,1;2,3,2],[3;5;1],[4 4 4]) %<-- Create a sptensor.
+
X is a sparse tensor of size 4 x 4 x 4 with 3 nonzeros
+	(2,2,1)     5
+	(2,3,2)     1
+	(4,4,4)     3
+
X(1,2,1) %<-- Extract the (1,2,1) element, which is zero.
+
+ans =
+
+     0
+
+
X(4,4,4) %<-- Extract the (4,4,4) element, which is nonzero.
+
+ans =
+
+     3
+
+
X(1:2,2:4,:) %<-- Extract a 2 x 3 x 4 subtensor.
+
ans is a sparse tensor of size 2 x 3 x 4 with 2 nonzeros
+	(2,1,1)     5
+	(2,2,2)     1
+
X([1 1 1; 2 2 1]) %<-- Extract elements by subscript.
+
+ans =
+
+     0
+     5
+
+
X([1;6]) %<-- Same as above but with linear indices.
+
+ans =
+
+     0
+     5
+
+

As with a tensor, subscriped reference may be ambiguous for one-dimensional tensors.

X = sptensor([1;3;5],1,7) %<-- Create a sparse tensor.
+
X is a sparse tensor of size 7 with 3 nonzeros
+	(1)     1
+	(3)     1
+	(5)     1
+
X(3) %<-- Fully specified, single elements are always returned as scalars.
+
+ans =
+
+     1
+
+
X([3;6]) %<-- Returns a subtensor.
+
ans is a sparse tensor of size 2 with 1 nonzeros
+	(1)     1
+
X([3;6],'extract') %<-- Same as above *but* returns an array.
+
+ans =
+
+     1
+     0
+
+

Subscripted assignment for a sptensor

X = sptensor([30 40 20]) %<-- Create an emtpy 30 x 40 x 20 sptensor.
+
X is an all-zero sparse tensor of size 30 x 40 x 20
+
X(30,40,20) = 7 %<-- Assign a single element.
+
X is a sparse tensor of size 30 x 40 x 20 with 1 nonzeros
+	(30,40,20)     7
+
X([1,1,1;2,2,2]) = [1;1] %<-- Assign a list of elements.
+
X is a sparse tensor of size 30 x 40 x 20 with 3 nonzeros
+	(30,40,20)     7
+	( 1, 1, 1)     1
+	( 2, 2, 2)     1
+
X(11:20,11:20,11:20) = sptenrand([10,10,10],10) %<-- Assign a subtensor.
+
X is a sparse tensor of size 30 x 40 x 20 with 13 nonzeros
+	(30,40,20)    7.0000
+	( 1, 1, 1)    1.0000
+	( 2, 2, 2)    1.0000
+	(12,13,15)    0.9342
+	(13,12,11)    0.2644
+	(13,12,16)    0.1603
+	(13,17,14)    0.8729
+	(15,13,14)    0.2379
+	(18,11,14)    0.6458
+	(19,11,14)    0.9669
+	(19,12,15)    0.6649
+	(19,19,12)    0.8704
+	(20,20,19)    0.0099
+
X(31,41,21) = 4 %<-- Grows the size of the sptensor.
+
X is a sparse tensor of size 31 x 41 x 21 with 14 nonzeros
+	(30,40,20)    7.0000
+	( 1, 1, 1)    1.0000
+	( 2, 2, 2)    1.0000
+	(12,13,15)    0.9342
+	(13,12,11)    0.2644
+	(13,12,16)    0.1603
+	(13,17,14)    0.8729
+	(15,13,14)    0.2379
+	(18,11,14)    0.6458
+	(19,11,14)    0.9669
+	(19,12,15)    0.6649
+	(19,19,12)    0.8704
+	(20,20,19)    0.0099
+	(31,41,21)    4.0000
+
X(111:120,111:120,111:120) = sptenrand([10,10,10],10) %<-- Grow more.
+
X is a sparse tensor of size 120 x 120 x 120 with 24 nonzeros
+	( 30, 40, 20)    7.0000
+	(  1,  1,  1)    1.0000
+	(  2,  2,  2)    1.0000
+	( 12, 13, 15)    0.9342
+	( 13, 12, 11)    0.2644
+	( 13, 12, 16)    0.1603
+	( 13, 17, 14)    0.8729
+	( 15, 13, 14)    0.2379
+	( 18, 11, 14)    0.6458
+	( 19, 11, 14)    0.9669
+	( 19, 12, 15)    0.6649
+	( 19, 19, 12)    0.8704
+	( 20, 20, 19)    0.0099
+	( 31, 41, 21)    4.0000
+	(112,111,118)    0.3759
+	(112,115,112)    0.0099
+	(112,115,113)    0.4199
+	(112,120,117)    0.7537
+	(114,115,115)    0.7939
+	(115,115,117)    0.9200
+	(117,115,116)    0.8447
+	(118,115,120)    0.3678
+	(119,119,111)    0.6208
+	(119,119,117)    0.7313
+

Use end as the last index.

X(end-10:end,end-10:end,end-5:end)  %<-- Same as X(108:118,110:120,115:120)
+
ans is a sparse tensor of size 11 x 11 x 6 with 7 nonzeros
+	( 3, 2,4)    0.3759
+	( 3,11,3)    0.7537
+	( 5, 6,1)    0.7939
+	( 6, 6,3)    0.9200
+	( 8, 6,2)    0.8447
+	( 9, 6,6)    0.3678
+	(10,10,3)    0.7313
+

Use elemfun to manipulate the nonzeros of a sptensor

The function elemfun is similar to spfun for sparse matrices.

X = sptenrand([10,10,10],3) %<-- Create some data.
+
X is a sparse tensor of size 10 x 10 x 10 with 3 nonzeros
+	( 2,7,10)    0.3919
+	( 6,6, 7)    0.6273
+	(10,3, 4)    0.6991
+
Z = elemfun(X, @sqrt) %<-- Square root of every nonzero.
+
Z is a sparse tensor of size 10 x 10 x 10 with 3 nonzeros
+	( 2,7,10)    0.6260
+	( 6,6, 7)    0.7920
+	(10,3, 4)    0.8361
+
Z = elemfun(X, @(x) x+1) %<-- Use a custom function.
+
Z is a sparse tensor of size 10 x 10 x 10 with 3 nonzeros
+	( 2,7,10)    1.3919
+	( 6,6, 7)    1.6273
+	(10,3, 4)    1.6991
+
Z = elemfun(X, @(x) x~=0) %<-- Set every nonzero to one.
+
Z is a sparse tensor of size 10 x 10 x 10 with 3 nonzeros
+	( 2,7,10)     1
+	( 6,6, 7)     1
+	(10,3, 4)     1
+
Z = ones(X) %<-- An easier way to change every nonzero to one.
+
Z is a sparse tensor of size 10 x 10 x 10 with 3 nonzeros
+	( 2,7,10)     1
+	( 6,6, 7)     1
+	(10,3, 4)     1
+

Basic operations (plus, minus, times, etc.) on a sptensor

A = sptensor(tensor(floor(5*rand(2,2,2)))) %<-- Create data.
+B = sptensor(tensor(floor(5*rand(2,2,2)))) %<-- Create more data.
+
A is a sparse tensor of size 2 x 2 x 2 with 8 nonzeros
+	(1,1,1)     1
+	(2,1,1)     2
+	(1,2,1)     3
+	(2,2,1)     4
+	(1,1,2)     1
+	(2,1,2)     2
+	(1,2,2)     2
+	(2,2,2)     2
+B is a sparse tensor of size 2 x 2 x 2 with 7 nonzeros
+	(1,1,1)     3
+	(2,1,1)     2
+	(1,2,1)     3
+	(2,2,1)     2
+	(2,1,2)     3
+	(1,2,2)     4
+	(2,2,2)     4
+
+A %<-- Calls uplus.
+
ans is a sparse tensor of size 2 x 2 x 2 with 8 nonzeros
+	(1,1,1)     1
+	(2,1,1)     2
+	(1,2,1)     3
+	(2,2,1)     4
+	(1,1,2)     1
+	(2,1,2)     2
+	(1,2,2)     2
+	(2,2,2)     2
+
-A %<-- Calls uminus.
+
ans is a sparse tensor of size 2 x 2 x 2 with 8 nonzeros
+	(1,1,1)    -1
+	(2,1,1)    -2
+	(1,2,1)    -3
+	(2,2,1)    -4
+	(1,1,2)    -1
+	(2,1,2)    -2
+	(1,2,2)    -2
+	(2,2,2)    -2
+
A+B %<-- Calls plus.
+
ans is a sparse tensor of size 2 x 2 x 2 with 8 nonzeros
+	(1,1,1)     4
+	(1,1,2)     1
+	(1,2,1)     6
+	(1,2,2)     6
+	(2,1,1)     4
+	(2,1,2)     5
+	(2,2,1)     6
+	(2,2,2)     6
+
A-B %<-- Calls minus.
+
ans is a sparse tensor of size 2 x 2 x 2 with 6 nonzeros
+	(1,1,1)    -2
+	(1,1,2)     1
+	(1,2,2)    -2
+	(2,1,2)    -1
+	(2,2,1)     2
+	(2,2,2)    -2
+
A.*B %<-- Calls times.
+
ans is a sparse tensor of size 2 x 2 x 2 with 7 nonzeros
+	(1,1,1)     3
+	(1,2,1)     9
+	(1,2,2)     8
+	(2,1,1)     4
+	(2,1,2)     6
+	(2,2,1)     8
+	(2,2,2)     8
+
5*A %<-- Calls mtimes.
+
ans is a sparse tensor of size 2 x 2 x 2 with 8 nonzeros
+	(1,1,1)     5
+	(1,1,2)     5
+	(1,2,1)    15
+	(1,2,2)    10
+	(2,1,1)    10
+	(2,1,2)    10
+	(2,2,1)    20
+	(2,2,2)    10
+
A./2 %<-- Calls rdivide.
+
ans is a sparse tensor of size 2 x 2 x 2 with 8 nonzeros
+	(1,1,1)    0.5000
+	(1,1,2)    0.5000
+	(1,2,1)    1.5000
+	(1,2,2)    1.0000
+	(2,1,1)    1.0000
+	(2,1,2)    1.0000
+	(2,2,1)    2.0000
+	(2,2,2)    1.0000
+

Elementwise divsion by another sptensor is allowed, but if the sparsity pattern of the denominator should be a superset of the numerator.

A./(A+B) %<-- Calls rdivide.
+
ans is a sparse tensor of size 2 x 2 x 2 with 8 nonzeros
+	(1,1,1)    0.2500
+	(1,1,2)    1.0000
+	(1,2,1)    0.5000
+	(1,2,2)    0.3333
+	(2,1,1)    0.5000
+	(2,1,2)    0.4000
+	(2,2,1)    0.6667
+	(2,2,2)    0.3333
+
A./B %<-- Uh-oh. Getting a divide by zero.
+
ans is a sparse tensor of size 2 x 2 x 2 with 8 nonzeros
+	(1,1,1)    0.3333
+	(1,1,2)       Inf
+	(1,2,1)    1.0000
+	(1,2,2)    0.5000
+	(2,1,1)    1.0000
+	(2,1,2)    0.6667
+	(2,2,1)    2.0000
+	(2,2,2)    0.5000
+

Use permute to reorder the modes of a sptensor

A = sptenrand([30 40 20 1], 5) %<-- Create data.
+
A is a sparse tensor of size 30 x 40 x 20 x 1 with 5 nonzeros
+	( 4,33, 8,1)    0.7505
+	(11,40, 6,1)    0.7400
+	(15,23, 2,1)    0.4319
+	(20,27,11,1)    0.6343
+	(22, 6,20,1)    0.8030
+
permute(A,[4 3 2 1]) %<-- Reorder the modes.
+
ans is a sparse tensor of size 1 x 20 x 40 x 30 with 5 nonzeros
+	(1, 8,33, 4)    0.7505
+	(1, 6,40,11)    0.7400
+	(1, 2,23,15)    0.4319
+	(1,11,27,20)    0.6343
+	(1,20, 6,22)    0.8030
+

Permute works correctly for a 1-dimensional sptensor.

X = sptenrand(40,4) %<-- Create data.
+
X is a sparse tensor of size 40 with 4 nonzeros
+	( 4)    0.2536
+	(25)    0.8735
+	(37)    0.5134
+	(38)    0.7327
+
permute(X,1) %<-- Permute.
+
ans is a sparse tensor of size 40 with 4 nonzeros
+	( 4)    0.2536
+	(25)    0.8735
+	(37)    0.5134
+	(38)    0.7327
+

Displaying a tensor

The function disp handles small and large elements appropriately, as well as aligning the indices.

X = sptensor([1 1 1]); %<-- Create an empty sptensor.
+X(1,1,1) = rand(1)*1e15; %<-- Insert a very big element.
+X(4,3,2) = rand(1)*1e-15; %<-- Insert a very small element.
+X(2,2,2) = rand(1); %<-- Insert a 'normal' element.
+disp(X)
+
ans is a sparse tensor of size 4 x 3 x 2 with 3 nonzeros
+  1.0e+014 *
+	(1,1,1)    4.2223
+	(4,3,2)    0.0000
+	(2,2,2)    0.0000
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/B1_tenmat_doc.html b/external/tensor_toolbox_2.5/doc/html/B1_tenmat_doc.html new file mode 100755 index 0000000..6b3f8fd --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/B1_tenmat_doc.html @@ -0,0 +1,481 @@ + + + + + Converting a tensor to a matrix and vice versa

Converting a tensor to a matrix and vice versa

We show how to convert a tensor to a matrix stored with extra information so that it can be converted back to a tensor. Converting to a matrix requies an ordered mapping of the tensor indices to the rows and the columns of the matrix.

Contents

Creating a tenmat (tensor as matrix) object

X = tensor(1:24,[3 2 2 2]) %<-- Create a tensor.
+
X is a tensor of size 3 x 2 x 2 x 2
+	X(:,:,1,1) = 
+	     1     4
+	     2     5
+	     3     6
+	X(:,:,2,1) = 
+	     7    10
+	     8    11
+	     9    12
+	X(:,:,1,2) = 
+	    13    16
+	    14    17
+	    15    18
+	X(:,:,2,2) = 
+	    19    22
+	    20    23
+	    21    24
+
A = tenmat(X,[1 2],[3 4]) %<-- Dims [1 2] map to rows, [3 4] to columns.
+
A is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	A.rindices = [ 1  2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 3  4 ] (modes of tensor corresponding to columns)
+	A.data = 
+		     1     7    13    19
+		     2     8    14    20
+		     3     9    15    21
+		     4    10    16    22
+		     5    11    17    23
+		     6    12    18    24
+
B = tenmat(X,[2 1],[3 4]) %<-- Order matters!
+
B is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	B.rindices = [ 2  1 ] (modes of tensor corresponding to rows)
+	B.cindices = [ 3  4 ] (modes of tensor corresponding to columns)
+	B.data = 
+		     1     7    13    19
+		     4    10    16    22
+		     2     8    14    20
+		     5    11    17    23
+		     3     9    15    21
+		     6    12    18    24
+
C = tenmat(X,[1 2],[4 3]) %<-- Order matters!
+
C is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	C.rindices = [ 1  2 ] (modes of tensor corresponding to rows)
+	C.cindices = [ 4  3 ] (modes of tensor corresponding to columns)
+	C.data = 
+		     1    13     7    19
+		     2    14     8    20
+		     3    15     9    21
+		     4    16    10    22
+		     5    17    11    23
+		     6    18    12    24
+

Creating a tenmat by specifying the dimensions mapped to the rows

If just the row indices are specified, then the columns are arranged in increasing order.

A = tenmat(X,1) %<-- Same as A = tenmat(X,1,2:4)
+
A is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	A.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
+	A.data = 
+		     1     4     7    10    13    16    19    22
+		     2     5     8    11    14    17    20    23
+		     3     6     9    12    15    18    21    24
+

Creating a tenmat by specifying the dimensions mapped to the columns

Likewise, just the columns can be specified if the 3rd argument is a 't'. The rows are arranged in increasing order.

A = tenmat(X, [2 3], 't') %<-- Same as A = tenmat(X,[1 4],[2 3]).
+
A is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	A.rindices = [ 1  4 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 2  3 ] (modes of tensor corresponding to columns)
+	A.data = 
+		     1     4     7    10
+		     2     5     8    11
+		     3     6     9    12
+		    13    16    19    22
+		    14    17    20    23
+		    15    18    21    24
+

Vectorize via tenmat

All the dimensions can be mapped to the rows or the columnns.

A = tenmat(X,1:4,'t') %<-- Map all the dimensions to the columns
+
A is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	A.rindices = [  ] (modes of tensor corresponding to rows)
+	A.cindices = [ 1  2  3  4 ] (modes of tensor corresponding to columns)
+	A.data = 
+		  Columns 1 through 11
+		     1     2     3     4     5     6     7     8     9    10    11
+		  Columns 12 through 22
+		    12    13    14    15    16    17    18    19    20    21    22
+		  Columns 23 through 24
+		    23    24
+

Alternative ordering for the columns for mode-n matricization

Mode-n matricization means that only mode n is mapped to the rows. Different column orderings are available.

A = tenmat(X,2) %<-- By default, columns are ordered as [1 3 4].
+
A is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 1  3  4 ] (modes of tensor corresponding to columns)
+	A.data = 
+		  Columns 1 through 11
+		     1     2     3     7     8     9    13    14    15    19    20
+		     4     5     6    10    11    12    16    17    18    22    23
+		  Column 12
+		    21
+		    24
+
A = tenmat(X,2,[3 1 4]) %<-- Explicit specification.
+
A is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 3  1  4 ] (modes of tensor corresponding to columns)
+	A.data = 
+		  Columns 1 through 11
+		     1     7     2     8     3     9    13    19    14    20    15
+		     4    10     5    11     6    12    16    22    17    23    18
+		  Column 12
+		    21
+		    24
+
A = tenmat(X,2,'fc') %<-- Forward cyclic, i.e., [3 4 1].
+
A is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 3  4  1 ] (modes of tensor corresponding to columns)
+	A.data = 
+		  Columns 1 through 11
+		     1     7    13    19     2     8    14    20     3     9    15
+		     4    10    16    22     5    11    17    23     6    12    18
+		  Column 12
+		    21
+		    24
+
A = tenmat(X,2,'bc') %<-- Backward cyclic, i.e., [1 4 3].
+
A is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	A.data = 
+		  Columns 1 through 11
+		     1     2     3    13    14    15     7     8     9    19    20
+		     4     5     6    16    17    18    10    11    12    22    23
+		  Column 12
+		    21
+		    24
+

Constituent parts of a tenmat

A.data %<-- The matrix itself.
+
+ans =
+
+  Columns 1 through 11
+
+     1     2     3    13    14    15     7     8     9    19    20
+     4     5     6    16    17    18    10    11    12    22    23
+
+  Column 12
+
+    21
+    24
+
+
A.tsize %<-- Size of the original tensor.
+
+ans =
+
+     3     2     2     2
+
+
A.rdims %<-- Dimensions that were mapped to the rows.
+
+ans =
+
+     2
+
+
A.cdims %<-- Dimensions that were mapped to the columns.
+
+ans =
+
+     1     4     3
+
+

Creating a tenmat from its constituent parts

B = tenmat(A.data,A.rdims,A.cdims,A.tsize) %<-- Recreates A
+
B is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	B.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	B.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	B.data = 
+		  Columns 1 through 11
+		     1     2     3    13    14    15     7     8     9    19    20
+		     4     5     6    16    17    18    10    11    12    22    23
+		  Column 12
+		    21
+		    24
+

Creating an empty tenmat

B = tenmat %<-- Empty tenmat.
+
B is a matrix corresponding to a tensor of size [empty tensor]
+	B.rindices = [  ] (modes of tensor corresponding to rows)
+	B.cindices = [  ] (modes of tensor corresponding to columns)
+	B.data = []
+

Use double to convert a tenmat to a MATLAB matrix

double(A) %<-- converts A to a standard matrix
+
+ans =
+
+  Columns 1 through 11
+
+     1     2     3    13    14    15     7     8     9    19    20
+     4     5     6    16    17    18    10    11    12    22    23
+
+  Column 12
+
+    21
+    24
+
+

Use tensor to convert a tenmat to a tensor

Y = tensor(A)
+
Y is a tensor of size 3 x 2 x 2 x 2
+	Y(:,:,1,1) = 
+	     1     4
+	     2     5
+	     3     6
+	Y(:,:,2,1) = 
+	     7    10
+	     8    11
+	     9    12
+	Y(:,:,1,2) = 
+	    13    16
+	    14    17
+	    15    18
+	Y(:,:,2,2) = 
+	    19    22
+	    20    23
+	    21    24
+

Use size and tsize for the dimensions of a tenmat

size(A) %<-- Matrix size
+tsize(A) %<-- Corresponding tensor size
+
+ans =
+
+     2    12
+
+
+ans =
+
+     3     2     2     2
+
+

Subscripted reference for a tenmat

A(2,1) %<-- returns the (2,1) element of the matrix.
+
+ans =
+
+     4
+
+

Subscripted assignment for a tenmat

A(1:2,1:2) = ones(2) %<-- Replace part of the matrix.
+
A is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	A.data = 
+		  Columns 1 through 11
+		     1     1     3    13    14    15     7     8     9    19    20
+		     1     1     6    16    17    18    10    11    12    22    23
+		  Column 12
+		    21
+		    24
+

Use end for the last index

A(end,end) %<-- Same as X(2,12)
+
+ans =
+
+    24
+
+

Basic operations for tenmat

norm(A) %<-- Norm of the matrix.
+
+ans =
+
+   69.6994
+
+
A' %<-- Calls ctranspose (also swaps mapped dimensions).
+
ans is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	ans.rindices = [ 1  4  3 ] (modes of tensor corresponding to rows)
+	ans.cindices = [ 2 ] (modes of tensor corresponding to columns)
+	ans.data = 
+		     1     1
+		     1     1
+		     3     6
+		    13    16
+		    14    17
+		    15    18
+		     7    10
+		     8    11
+		     9    12
+		    19    22
+		    20    23
+		    21    24
+
+A %<-- Calls uplus.
+
ans is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	ans.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	ans.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	ans.data = 
+		  Columns 1 through 11
+		     1     1     3    13    14    15     7     8     9    19    20
+		     1     1     6    16    17    18    10    11    12    22    23
+		  Column 12
+		    21
+		    24
+
-A %<-- Calls uminus.
+
ans is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	ans.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	ans.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	ans.data = 
+		  Columns 1 through 11
+		    -1    -1    -3   -13   -14   -15    -7    -8    -9   -19   -20
+		    -1    -1    -6   -16   -17   -18   -10   -11   -12   -22   -23
+		  Column 12
+		   -21
+		   -24
+
A+A %<-- Calls plus.
+
ans is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	ans.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	ans.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	ans.data = 
+		  Columns 1 through 11
+		     2     2     6    26    28    30    14    16    18    38    40
+		     2     2    12    32    34    36    20    22    24    44    46
+		  Column 12
+		    42
+		    48
+
A-A %<-- Calls minus.
+
ans is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	ans.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	ans.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	ans.data = 
+		  Columns 1 through 11
+		     0     0     0     0     0     0     0     0     0     0     0
+		     0     0     0     0     0     0     0     0     0     0     0
+		  Column 12
+		     0
+		     0
+

Multiplying two tenmats

It is possible to compute the product of two tenmats and have a result that can be converted into a tensor.

B = A * A' %<-- Tenmat that is the product of two tenmats.
+
B is a matrix corresponding to a tensor of size 2 x 2
+	B.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	B.cindices = [ 2 ] (modes of tensor corresponding to columns)
+	B.data = 
+		        1997        2384
+		        2384        2861
+
tensor(B) %<-- Corresponding tensor.
+
ans is a tensor of size 2 x 2
+	ans(:,:) = 
+	        1997        2384
+	        2384        2861
+

Displaying a tenmat

Shows the original tensor dimensions, the modes mapped to rows, the modes mapped to columns, and the matrix.

disp(A)
+
ans is a matrix corresponding to a tensor of size 3 x 2 x 2 x 2
+	ans.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	ans.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	ans.data = 
+		  Columns 1 through 11
+		     1     1     3    13    14    15     7     8     9    19    20
+		     1     1     6    16    17    18    10    11    12    22    23
+		  Column 12
+		    21
+		    24
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/B2_sptenmat_doc.html b/external/tensor_toolbox_2.5/doc/html/B2_sptenmat_doc.html new file mode 100755 index 0000000..0303ff0 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/B2_sptenmat_doc.html @@ -0,0 +1,561 @@ + + + + + Converting sparse tensors to matrices and vice versa

Converting sparse tensors to matrices and vice versa

We show how to convert a sptensor to a matrix stored in coordinate format and with extra information so that it can be converted back to a sptensor.

Contents

Creating a sptenmat (sparse tensor as sparse matrix) object

A sparse tensor can be converted to a sparse matrix. The matrix, however, is not stored as a MATLAB sparse matrix because that format is sometimes inefficient for converted sparse tensors. Instead, the row and column indices are stored explicitly.

First, we create a sparse tensor to be converted.

X = sptenrand([10 10 10 10],10) %<-- Generate some data.
+
X is a sparse tensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	(1,9, 5, 1)    0.4249
+	(3,2, 1, 2)    0.3756
+	(4,7,10, 9)    0.1662
+	(4,8, 3,10)    0.8332
+	(5,3, 4, 8)    0.8386
+	(5,3, 6, 7)    0.4516
+	(6,7, 5, 1)    0.9566
+	(6,7, 6, 6)    0.1472
+	(7,8, 5, 6)    0.8699
+	(9,9, 1, 9)    0.7694
+

All the same options for tenmat are available as for tenmat.

A = sptenmat(X,1) %<-- Mode-1 matricization.
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	A.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
+	(1, 49)	0.424889
+	(3,102)	0.375577
+	(4,897)	0.166154
+	(4,928)	0.833151
+	(5,733)	0.83864
+	(5,653)	0.451614
+	(6, 47)	0.956601
+	(6,557)	0.147153
+	(7,548)	0.869933
+	(9,809)	0.769436
+
A = sptenmat(X,[2 3]) %<-- More than one mode is mapped to the columns.
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	A.rindices = [ 2  3 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 1  4 ] (modes of tensor corresponding to columns)
+	(49, 1)	0.424889
+	( 2,13)	0.375577
+	(97,84)	0.166154
+	(28,94)	0.833151
+	(33,75)	0.83864
+	(53,65)	0.451614
+	(47, 6)	0.956601
+	(57,56)	0.147153
+	(48,57)	0.869933
+	( 9,89)	0.769436
+
A = sptenmat(X,[2 3],'t') %<-- Specify column dimensions (transpose).
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	A.rindices = [ 1  4 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 2  3 ] (modes of tensor corresponding to columns)
+	( 1,49)	0.424889
+	(13, 2)	0.375577
+	(84,97)	0.166154
+	(94,28)	0.833151
+	(75,33)	0.83864
+	(65,53)	0.451614
+	( 6,47)	0.956601
+	(56,57)	0.147153
+	(57,48)	0.869933
+	(89, 9)	0.769436
+
A = sptenmat(X,1:4) %<-- All modes mapped to rows, i.e., vectorize.
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	A.rindices = [ 1  2  3  4 ] (modes of tensor corresponding to rows)
+	A.cindices = [  ] (modes of tensor corresponding to columns)
+	( 481,1)	0.424889
+	(1013,1)	0.375577
+	(8964,1)	0.166154
+	(9274,1)	0.833151
+	(7325,1)	0.83864
+	(6525,1)	0.451614
+	( 466,1)	0.956601
+	(5566,1)	0.147153
+	(5477,1)	0.869933
+	(8089,1)	0.769436
+
A = sptenmat(X,2) %<-- By default, columns are ordered as [1 3 4].
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 1  3  4 ] (modes of tensor corresponding to columns)
+	(9, 41)	0.424889
+	(2,103)	0.375577
+	(7,894)	0.166154
+	(8,924)	0.833151
+	(3,735)	0.83864
+	(3,655)	0.451614
+	(7, 46)	0.956601
+	(7,556)	0.147153
+	(8,547)	0.869933
+	(9,809)	0.769436
+
A = sptenmat(X,2,[3 1 4]) %<-- Explicit column ordering.
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 3  1  4 ] (modes of tensor corresponding to columns)
+	(9,  5)	0.424889
+	(2,121)	0.375577
+	(7,840)	0.166154
+	(8,933)	0.833151
+	(3,744)	0.83864
+	(3,646)	0.451614
+	(7, 55)	0.956601
+	(7,556)	0.147153
+	(8,565)	0.869933
+	(9,881)	0.769436
+
A = sptenmat(X,2,'fc') %<-- Foward cyclic.
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 3  4  1 ] (modes of tensor corresponding to columns)
+	(9,  5)	0.424889
+	(2,211)	0.375577
+	(7,390)	0.166154
+	(8,393)	0.833151
+	(3,474)	0.83864
+	(3,466)	0.451614
+	(7,505)	0.956601
+	(7,556)	0.147153
+	(8,655)	0.869933
+	(9,881)	0.769436
+
A = sptenmat(X,2,'bc') %<-- Backward cyclic.
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	(9,401)	0.424889
+	(2, 13)	0.375577
+	(7,984)	0.166154
+	(8,294)	0.833151
+	(3,375)	0.83864
+	(3,565)	0.451614
+	(7,406)	0.956601
+	(7,556)	0.147153
+	(8,457)	0.869933
+	(9, 89)	0.769436
+

Constituent parts of a sptenmat

A.subs %<-- Subscripts of the nonzeros.
+
+ans =
+
+     9   401
+     2    13
+     7   984
+     8   294
+     3   375
+     3   565
+     7   406
+     7   556
+     8   457
+     9    89
+
+
A.vals %<-- The corresponding nonzero values.
+
+ans =
+
+    0.4249
+    0.3756
+    0.1662
+    0.8332
+    0.8386
+    0.4516
+    0.9566
+    0.1472
+    0.8699
+    0.7694
+
+
A.tsize %<-- Size of the original tensor.
+
+ans =
+
+    10    10    10    10
+
+
A.rdims %<-- Dimensions that were mapped to the rows.
+
+ans =
+
+     2
+
+
A.cdims %<-- Dimensions that were mapped to the columns.
+
+ans =
+
+     1     4     3
+
+

Creating a sptenmat from its constituent parts

B = sptenmat(A.subs,A.vals,A.rdims,A.cdims,A.tsize) %<-- Copies A
+
B is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	B.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	B.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	(2, 13)	0.375577
+	(3,375)	0.83864
+	(3,565)	0.451614
+	(7,406)	0.956601
+	(7,556)	0.147153
+	(7,984)	0.166154
+	(8,294)	0.833151
+	(8,457)	0.869933
+	(9, 89)	0.769436
+	(9,401)	0.424889
+
B = sptenmat(double(A),A.rdims,A.cdims,A.tsize) %<-- More efficient to pass a matrix.
+
B is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	B.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	B.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+	(2, 13)	0.375577
+	(9, 89)	0.769436
+	(8,294)	0.833151
+	(3,375)	0.83864
+	(9,401)	0.424889
+	(7,406)	0.956601
+	(8,457)	0.869933
+	(7,556)	0.147153
+	(3,565)	0.451614
+	(7,984)	0.166154
+

Creating a sptenmat with no nonzeros

A = sptenmat([],[],A.rdims,A.cdims,A.tsize) %<-- An empty sptenmat.
+
A is an all-zero sptenmat from an sptensor of size 10 x 10 x 10 x 10
+	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
+

Creating an emtpy sptenmat

A = sptenmat %<-- A really empty sptenmat.
+
A is an all-zero sptenmat from an sptensor of size [empty tensor]
+	A.rindices = [  ] (modes of tensor corresponding to rows)
+	A.cindices = [  ] (modes of tensor corresponding to columns)
+

Use double to convert a sptenmat to a MATLAB sparse matrix

X = sptenrand([10 10 10 10],10); %<-- Create a tensor.
+A = sptenmat(X,1) %<-- Convert it to a sptenmat
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	A.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
+	( 2,723)	0.783859
+	( 3, 32)	0.986158
+	( 4,647)	0.473343
+	( 5,775)	0.902819
+	( 5,236)	0.451059
+	( 5,256)	0.804517
+	( 5,357)	0.828864
+	( 7,191)	0.16627
+	( 7,447)	0.393906
+	(10,434)	0.520757
+
B = double(A) %<-- Convert it to a MATLAB sparse matrix
+
+B =
+
+   (3,32)      0.9862
+   (7,191)     0.1663
+   (5,236)     0.4511
+   (5,256)     0.8045
+   (5,357)     0.8289
+  (10,434)     0.5208
+   (7,447)     0.3939
+   (4,647)     0.4733
+   (2,723)     0.7839
+   (5,775)     0.9028
+
+
whos A B %<-- The storage for B (the sparse matrix) is larger than for A.
+
  Name       Size              Bytes  Class       Attributes
+
+  A         10x1000             1184  sptenmat              
+  B         10x1000             8168  double      sparse    
+
+
C = B'; %<-- Transposing the result fixes the problem.
+whos C
+
  Name         Size            Bytes  Class     Attributes
+
+  C         1000x10              248  double    sparse    
+
+

Use full to convert a sptenmat to a tenmat

B = sptenmat(sptenrand([3 3 3], 3), 1) %<-- Create a sptenmat
+
B is a sptenmat from an sptensor of size 3 x 3 x 3 with 3 nonzeros
+	B.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	B.cindices = [ 2  3 ] (modes of tensor corresponding to columns)
+	(2,1)	0.759479
+	(2,8)	0.949759
+	(3,5)	0.557939
+
C = full(B) %<-- Convert to a tenmat
+
C is a matrix corresponding to a tensor of size 3 x 3 x 3
+	C.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	C.cindices = [ 2  3 ] (modes of tensor corresponding to columns)
+	C.data = 
+		  Columns 1 through 7
+		         0         0         0         0         0         0         0
+		    0.7595         0         0         0         0         0         0
+		         0         0         0         0    0.5579         0         0
+		  Columns 8 through 9
+		         0         0
+		    0.9498         0
+		         0         0
+

Use sptensor to convert a sptenmat to a sptensor

Y = sptensor(A) %<-- Convert a sptenmat to a sptensor
+
Y is a sparse tensor of size 10 x 10 x 10 x 10 with 10 nonzeros
+	( 2,3, 3,8)    0.7839
+	( 3,2, 4,1)    0.9862
+	( 4,7, 5,7)    0.4733
+	( 5,5, 8,8)    0.9028
+	( 5,6, 4,3)    0.4511
+	( 5,6, 6,3)    0.8045
+	( 5,7, 6,4)    0.8289
+	( 7,1,10,2)    0.1663
+	( 7,7, 5,5)    0.3939
+	(10,4, 4,5)    0.5208
+

Use size and tsize for the dimensions of a sptenmat

size(A) %<-- Matrix size
+tsize(A) %<-- Corresponding tensor size
+
+ans =
+
+          10        1000
+
+
+ans =
+
+    10    10    10    10
+
+

Subscripted reference for a sptenmat

This is not supported beyond getting the constituent parts.

Subscripted assignment for a sptenmat

A(1:2,1:2) = ones(2) %<-- Replace part of the matrix.
+
A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 14 nonzeros
+	A.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	A.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
+	( 1,  1)	1
+	( 1,  2)	1
+	( 2,  1)	1
+	( 2,  2)	1
+	( 2,723)	0.783859
+	( 3, 32)	0.986158
+	( 4,647)	0.473343
+	( 5,236)	0.451059
+	( 5,256)	0.804517
+	( 5,357)	0.828864
+	( 5,775)	0.902819
+	( 7,191)	0.16627
+	( 7,447)	0.393906
+	(10,434)	0.520757
+

Use end for the last index

End is not supported.

Basic operations for sptenmat

norm(A) %<-- Norm of the matrix.
+
+ans =
+
+    2.9356
+
+
+A %<-- Calls uplus.
+
ans is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 14 nonzeros
+	ans.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	ans.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
+	( 1,  1)	1
+	( 1,  2)	1
+	( 2,  1)	1
+	( 2,  2)	1
+	( 2,723)	0.783859
+	( 3, 32)	0.986158
+	( 4,647)	0.473343
+	( 5,236)	0.451059
+	( 5,256)	0.804517
+	( 5,357)	0.828864
+	( 5,775)	0.902819
+	( 7,191)	0.16627
+	( 7,447)	0.393906
+	(10,434)	0.520757
+
-A %<-- Calls uminus.
+
ans is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 14 nonzeros
+	ans.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	ans.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
+	( 1,  1)	-1
+	( 1,  2)	-1
+	( 2,  1)	-1
+	( 2,  2)	-1
+	( 2,723)	-0.783859
+	( 3, 32)	-0.986158
+	( 4,647)	-0.473343
+	( 5,236)	-0.451059
+	( 5,256)	-0.804517
+	( 5,357)	-0.828864
+	( 5,775)	-0.902819
+	( 7,191)	-0.16627
+	( 7,447)	-0.393906
+	(10,434)	-0.520757
+

Use aatx to efficiently compute A * A' * x for a sptenmat

x = ones(10,1); %<-- Create vector
+aatx(A,x) %<-- Compute A * A' * x
+
+ans =
+
+    4.0000
+    4.6144
+    0.9725
+    0.2241
+    2.3528
+         0
+    0.1828
+         0
+         0
+    0.2712
+
+
double(A) * double(A)' * x %<-- Same as above but less efficient
+
+ans =
+
+    4.0000
+    4.6144
+    0.9725
+    0.2241
+    2.3528
+         0
+    0.1828
+         0
+         0
+    0.2712
+
+

Displaying a tenmat

Shows the original tensor dimensions, the modes mapped to rows, the modes mapped to columns, and the matrix.

disp(A)
+
ans is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 14 nonzeros
+	ans.rindices = [ 1 ] (modes of tensor corresponding to rows)
+	ans.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
+	( 1,  1)	1
+	( 1,  2)	1
+	( 2,  1)	1
+	( 2,  2)	1
+	( 2,723)	0.783859
+	( 3, 32)	0.986158
+	( 4,647)	0.473343
+	( 5,236)	0.451059
+	( 5,256)	0.804517
+	( 5,357)	0.828864
+	( 5,775)	0.902819
+	( 7,191)	0.16627
+	( 7,447)	0.393906
+	(10,434)	0.520757
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/C_ttensor_doc.html b/external/tensor_toolbox_2.5/doc/html/C_ttensor_doc.html new file mode 100755 index 0000000..046badb --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/C_ttensor_doc.html @@ -0,0 +1,621 @@ + + + + + Tucker Tensors

Tucker Tensors

Tucker format is a decomposition of a tensor X as the product of a core tensor G and matrices (e.g., A,B,C) in each dimension. In other words, a tensor X is expressed as:

$${\mathcal X} = {\mathcal G} \times_1 A \times_2 B \times_2 C$$

In MATLAB notation, X=ttm(G,{A,B,C}). The ttensor class stores the components of the tensor X and can perform many operations, e.g., ttm, without explicitly forming the tensor X.

Contents

Creating a ttensor with a tensor core

core = tensor(rand(3,2,1),[3 2 1]); %<-- The core tensor.
+U = {rand(5,3), rand(4,2), rand(3,1)}; %<-- The matrices.
+X = ttensor(core,U) %<-- Create the ttensor.
+
X is a ttensor of size 5 x 4 x 3
+	X.core is a tensor of size 3 x 2 x 1
+		X.core(:,:,1) = 
+	    0.0142    0.9771
+	    0.5962    0.2219
+	    0.8162    0.7037
+	X.U{1} = 
+		    0.5221    0.1722    0.8948
+		    0.9329    0.9688    0.2861
+		    0.7134    0.3557    0.2512
+		    0.2280    0.0490    0.9327
+		    0.4496    0.7553    0.1310
+	X.U{2} = 
+		    0.9408    0.4551
+		    0.7019    0.0811
+		    0.8477    0.8511
+		    0.2093    0.5620
+	X.U{3} = 
+		    0.3193
+		    0.3749
+		    0.8678
+

Alternate core formats: sptensor, ktensor, or ttensor

core1 = sptenrand([3 2 1],3); %<-- Create a 3 x 2 x 1 sptensor.
+Y = ttensor(core1,U) %<-- Core is a sptensor.
+
Y is a ttensor of size 5 x 4 x 3
+	Y.core is a sparse tensor of size 3 x 2 x 1 with 3 nonzeros
+	(1,1,1)    0.3751
+	(1,2,1)    0.8234
+	(2,1,1)    0.0466
+	Y.U{1} = 
+		    0.5221    0.1722    0.8948
+		    0.9329    0.9688    0.2861
+		    0.7134    0.3557    0.2512
+		    0.2280    0.0490    0.9327
+		    0.4496    0.7553    0.1310
+	Y.U{2} = 
+		    0.9408    0.4551
+		    0.7019    0.0811
+		    0.8477    0.8511
+		    0.2093    0.5620
+	Y.U{3} = 
+		    0.3193
+		    0.3749
+		    0.8678
+
V = {rand(3,2),rand(2,2),rand(1,2)}; %<-- Create some random matrices.
+core2 = ktensor(V); %<-- Create a 3 x 2 x 1 ktensor.
+Y = ttensor(core2,U) %<-- Core is a ktensor.
+
Y is a ttensor of size 5 x 4 x 3
+	Y.core is a ktensor of size 3 x 2 x 1
+		Y.core.lambda = [ 1  1 ]
+		Y.core.U{1} = 
+		    0.5979    0.8888
+		    0.9492    0.1016
+		    0.2888    0.0653
+		Y.core.U{2} = 
+		    0.2343    0.0631
+		    0.9331    0.2642
+		Y.core.U{3} = 
+		    0.9995    0.2120
+	Y.U{1} = 
+		    0.5221    0.1722    0.8948
+		    0.9329    0.9688    0.2861
+		    0.7134    0.3557    0.2512
+		    0.2280    0.0490    0.9327
+		    0.4496    0.7553    0.1310
+	Y.U{2} = 
+		    0.9408    0.4551
+		    0.7019    0.0811
+		    0.8477    0.8511
+		    0.2093    0.5620
+	Y.U{3} = 
+		    0.3193
+		    0.3749
+		    0.8678
+
core3 = ttensor(tensor(1:8,[2 2 2]),V); %<-- Create a 3 x 2 x 1 ttensor.
+Y = ttensor(core3,U) %<-- Core is a ttensor.
+
Y is a ttensor of size 5 x 4 x 3
+	Y.core is a ttensor of size 3 x 2 x 1
+		Y.core.core is a tensor of size 2 x 2 x 2
+			Y.core.core(:,:,1) = 
+	     1     3
+	     2     4
+			Y.core.core(:,:,2) = 
+	     5     7
+	     6     8
+		Y.core.U{1} = 
+		    0.5979    0.8888
+		    0.9492    0.1016
+		    0.2888    0.0653
+		Y.core.U{2} = 
+		    0.2343    0.0631
+		    0.9331    0.2642
+		Y.core.U{3} = 
+		    0.9995    0.2120
+	Y.U{1} = 
+		    0.5221    0.1722    0.8948
+		    0.9329    0.9688    0.2861
+		    0.7134    0.3557    0.2512
+		    0.2280    0.0490    0.9327
+		    0.4496    0.7553    0.1310
+	Y.U{2} = 
+		    0.9408    0.4551
+		    0.7019    0.0811
+		    0.8477    0.8511
+		    0.2093    0.5620
+	Y.U{3} = 
+		    0.3193
+		    0.3749
+		    0.8678
+

Creating a one-dimensional ttensor

Z = ttensor(tensor(rand(2,1),2), rand(4,2)) %<-- One-dimensional ttensor.
+
Z is a ttensor of size 4
+	Z.core is a tensor of size 2
+		Z.core(:) = 
+	    0.4984
+	    0.2905
+	Z.U{1} = 
+		    0.6728    0.1309
+		    0.9580    0.0954
+		    0.7666    0.0149
+		    0.6661    0.2882
+

Constituent parts of a ttensor

X.core %<-- Core tensor.
+
ans is a tensor of size 3 x 2 x 1
+	ans(:,:,1) = 
+	    0.0142    0.9771
+	    0.5962    0.2219
+	    0.8162    0.7037
+
X.U %<-- Cell array of matrices.
+
+ans = 
+
+    [5x3 double]    [4x2 double]    [3x1 double]
+
+

Creating a ttensor from its constituent parts

Y = ttensor(X.core,X.U) %<-- Recreate a tensor from its parts.
+
Y is a ttensor of size 5 x 4 x 3
+	Y.core is a tensor of size 3 x 2 x 1
+		Y.core(:,:,1) = 
+	    0.0142    0.9771
+	    0.5962    0.2219
+	    0.8162    0.7037
+	Y.U{1} = 
+		    0.5221    0.1722    0.8948
+		    0.9329    0.9688    0.2861
+		    0.7134    0.3557    0.2512
+		    0.2280    0.0490    0.9327
+		    0.4496    0.7553    0.1310
+	Y.U{2} = 
+		    0.9408    0.4551
+		    0.7019    0.0811
+		    0.8477    0.8511
+		    0.2093    0.5620
+	Y.U{3} = 
+		    0.3193
+		    0.3749
+		    0.8678
+

Creating an empty ttensor.

X = ttensor %<-- empty ttensor
+
X is a ttensor of size [empty tensor]
+	X.core is a tensor of size [empty tensor]
+		X.core = []
+

Use full or tensor to convert a ttensor to a tensor

X = ttensor(core,U) %<-- Create a tensor
+
X is a ttensor of size 5 x 4 x 3
+	X.core is a tensor of size 3 x 2 x 1
+		X.core(:,:,1) = 
+	    0.0142    0.9771
+	    0.5962    0.2219
+	    0.8162    0.7037
+	X.U{1} = 
+		    0.5221    0.1722    0.8948
+		    0.9329    0.9688    0.2861
+		    0.7134    0.3557    0.2512
+		    0.2280    0.0490    0.9327
+		    0.4496    0.7553    0.1310
+	X.U{2} = 
+		    0.9408    0.4551
+		    0.7019    0.0811
+		    0.8477    0.8511
+		    0.2093    0.5620
+	X.U{3} = 
+		    0.3193
+		    0.3749
+		    0.8678
+
full(X) %<-- Converts to a tensor.
+
ans is a tensor of size 5 x 4 x 3
+	ans(:,:,1) = 
+	    0.4236    0.2188    0.5476    0.2676
+	    0.4406    0.2191    0.5840    0.2934
+	    0.2668    0.1204    0.3746    0.1995
+	    0.3678    0.2009    0.4567    0.2128
+	    0.2709    0.1444    0.3425    0.1631
+	ans(:,:,2) = 
+	    0.4974    0.2569    0.6430    0.3142
+	    0.5173    0.2573    0.6857    0.3445
+	    0.3132    0.1414    0.4398    0.2343
+	    0.4318    0.2359    0.5363    0.2498
+	    0.3181    0.1696    0.4022    0.1915
+	ans(:,:,3) = 
+	    1.1514    0.5948    1.4883    0.7272
+	    1.1975    0.5956    1.5872    0.7974
+	    0.7251    0.3273    1.0180    0.5423
+	    0.9996    0.5461    1.2413    0.5783
+	    0.7363    0.3925    0.9310    0.4434
+
tensor(X) %<-- Also converts to a tensor.
+
ans is a tensor of size 5 x 4 x 3
+	ans(:,:,1) = 
+	    0.4236    0.2188    0.5476    0.2676
+	    0.4406    0.2191    0.5840    0.2934
+	    0.2668    0.1204    0.3746    0.1995
+	    0.3678    0.2009    0.4567    0.2128
+	    0.2709    0.1444    0.3425    0.1631
+	ans(:,:,2) = 
+	    0.4974    0.2569    0.6430    0.3142
+	    0.5173    0.2573    0.6857    0.3445
+	    0.3132    0.1414    0.4398    0.2343
+	    0.4318    0.2359    0.5363    0.2498
+	    0.3181    0.1696    0.4022    0.1915
+	ans(:,:,3) = 
+	    1.1514    0.5948    1.4883    0.7272
+	    1.1975    0.5956    1.5872    0.7974
+	    0.7251    0.3273    1.0180    0.5423
+	    0.9996    0.5461    1.2413    0.5783
+	    0.7363    0.3925    0.9310    0.4434
+

Use double to convert a ttensor to a (multidimensional) array

double(X) %<-- Converts to a MATLAB array
+
+ans(:,:,1) =
+
+    0.4236    0.2188    0.5476    0.2676
+    0.4406    0.2191    0.5840    0.2934
+    0.2668    0.1204    0.3746    0.1995
+    0.3678    0.2009    0.4567    0.2128
+    0.2709    0.1444    0.3425    0.1631
+
+
+ans(:,:,2) =
+
+    0.4974    0.2569    0.6430    0.3142
+    0.5173    0.2573    0.6857    0.3445
+    0.3132    0.1414    0.4398    0.2343
+    0.4318    0.2359    0.5363    0.2498
+    0.3181    0.1696    0.4022    0.1915
+
+
+ans(:,:,3) =
+
+    1.1514    0.5948    1.4883    0.7272
+    1.1975    0.5956    1.5872    0.7974
+    0.7251    0.3273    1.0180    0.5423
+    0.9996    0.5461    1.2413    0.5783
+    0.7363    0.3925    0.9310    0.4434
+
+

Use ndims and size to get the size of a ttensor

ndims(X) %<-- Number of dimensions.
+
+ans =
+
+     3
+
+
size(X) %<-- Row vector of the sizes.
+
+ans =
+
+     5     4     3
+
+
size(X,2) %<-- Size of the 2nd mode.
+
+ans =
+
+     4
+
+

Subscripted reference to a ttensor

X.core(1,1,1) %<-- Access an element of the core.
+
+ans =
+
+    0.0142
+
+
X.U{2} %<-- Extract a matrix.
+
+ans =
+
+    0.9408    0.4551
+    0.7019    0.0811
+    0.8477    0.8511
+    0.2093    0.5620
+
+
X{2} %<-- Same as above.
+
+ans =
+
+    0.9408    0.4551
+    0.7019    0.0811
+    0.8477    0.8511
+    0.2093    0.5620
+
+

Subscripted assignment for a ttensor

X.core = tenones(size(X.core)) %<-- Insert a new core.
+
X is a ttensor of size 5 x 4 x 3
+	X.core is a tensor of size 3 x 2 x 1
+		X.core(:,:,1) = 
+	     1     1
+	     1     1
+	     1     1
+	X.U{1} = 
+		    0.5221    0.1722    0.8948
+		    0.9329    0.9688    0.2861
+		    0.7134    0.3557    0.2512
+		    0.2280    0.0490    0.9327
+		    0.4496    0.7553    0.1310
+	X.U{2} = 
+		    0.9408    0.4551
+		    0.7019    0.0811
+		    0.8477    0.8511
+		    0.2093    0.5620
+	X.U{3} = 
+		    0.3193
+		    0.3749
+		    0.8678
+
X.core(2,2,1) = 7 %<-- Change a single element.
+
X is a ttensor of size 5 x 4 x 3
+	X.core is a tensor of size 3 x 2 x 1
+		X.core(:,:,1) = 
+	     1     1
+	     1     7
+	     1     1
+	X.U{1} = 
+		    0.5221    0.1722    0.8948
+		    0.9329    0.9688    0.2861
+		    0.7134    0.3557    0.2512
+		    0.2280    0.0490    0.9327
+		    0.4496    0.7553    0.1310
+	X.U{2} = 
+		    0.9408    0.4551
+		    0.7019    0.0811
+		    0.8477    0.8511
+		    0.2093    0.5620
+	X.U{3} = 
+		    0.3193
+		    0.3749
+		    0.8678
+
X{3}(1:2,1) = [1;1] %<-- Change the matrix for mode 3.
+
X is a ttensor of size 5 x 4 x 3
+	X.core is a tensor of size 3 x 2 x 1
+		X.core(:,:,1) = 
+	     1     1
+	     1     7
+	     1     1
+	X.U{1} = 
+		    0.5221    0.1722    0.8948
+		    0.9329    0.9688    0.2861
+		    0.7134    0.3557    0.2512
+		    0.2280    0.0490    0.9327
+		    0.4496    0.7553    0.1310
+	X.U{2} = 
+		    0.9408    0.4551
+		    0.7019    0.0811
+		    0.8477    0.8511
+		    0.2093    0.5620
+	X.U{3} = 
+		    1.0000
+		    1.0000
+		    0.8678
+

Using end for last index

X{end}  %<-- The same as X{3}.
+
+ans =
+
+    1.0000
+    1.0000
+    0.8678
+
+

Basic operations (uplus, uminus, mtimes) for a ttensor.

X = ttensor(tenrand([2 2 2]),{rand(3,2),rand(1,2),rand(2,2)}) %<-- Data.
++X %<-- Calls uplus.
+
X is a ttensor of size 3 x 1 x 2
+	X.core is a tensor of size 2 x 2 x 2
+		X.core(:,:,1) = 
+	    0.8167    0.0174
+	    0.9855    0.8194
+		X.core(:,:,2) = 
+	    0.6211    0.2440
+	    0.5602    0.8220
+	X.U{1} = 
+		    0.2632    0.2141
+		    0.7536    0.6021
+		    0.6596    0.6049
+	X.U{2} = 
+		    0.6595    0.1834
+	X.U{3} = 
+		    0.6365    0.5396
+		    0.1703    0.6234
+ans is a ttensor of size 3 x 1 x 2
+	ans.core is a tensor of size 2 x 2 x 2
+		ans.core(:,:,1) = 
+	    0.8167    0.0174
+	    0.9855    0.8194
+		ans.core(:,:,2) = 
+	    0.6211    0.2440
+	    0.5602    0.8220
+	ans.U{1} = 
+		    0.2632    0.2141
+		    0.7536    0.6021
+		    0.6596    0.6049
+	ans.U{2} = 
+		    0.6595    0.1834
+	ans.U{3} = 
+		    0.6365    0.5396
+		    0.1703    0.6234
+
-X %<-- Calls uminus.
+
ans is a ttensor of size 3 x 1 x 2
+	ans.core is a tensor of size 2 x 2 x 2
+		ans.core(:,:,1) = 
+	   -0.8167   -0.0174
+	   -0.9855   -0.8194
+		ans.core(:,:,2) = 
+	   -0.6211   -0.2440
+	   -0.5602   -0.8220
+	ans.U{1} = 
+		    0.2632    0.2141
+		    0.7536    0.6021
+		    0.6596    0.6049
+	ans.U{2} = 
+		    0.6595    0.1834
+	ans.U{3} = 
+		    0.6365    0.5396
+		    0.1703    0.6234
+
5*X %<-- Calls mtimes.
+
ans is a ttensor of size 3 x 1 x 2
+	ans.core is a tensor of size 2 x 2 x 2
+		ans.core(:,:,1) = 
+	    4.0837    0.0868
+	    4.9274    4.0970
+		ans.core(:,:,2) = 
+	    3.1057    1.2202
+	    2.8011    4.1100
+	ans.U{1} = 
+		    0.2632    0.2141
+		    0.7536    0.6021
+		    0.6596    0.6049
+	ans.U{2} = 
+		    0.6595    0.1834
+	ans.U{3} = 
+		    0.6365    0.5396
+		    0.1703    0.6234
+

Use permute to reorder the modes of a ttensor

permute(X,[3 2 1]) %<-- Reverses the modes of X
+
ans is a ttensor of size 2 x 1 x 3
+	ans.core is a tensor of size 2 x 2 x 2
+		ans.core(:,:,1) = 
+	    0.8167    0.0174
+	    0.6211    0.2440
+		ans.core(:,:,2) = 
+	    0.9855    0.8194
+	    0.5602    0.8220
+	ans.U{1} = 
+		    0.6365    0.5396
+		    0.1703    0.6234
+	ans.U{2} = 
+		    0.6595    0.1834
+	ans.U{3} = 
+		    0.2632    0.2141
+		    0.7536    0.6021
+		    0.6596    0.6049
+

Displaying a ttensor

The tensor displays by displaying the core and each of the component matrices.

disp(X) %<-- Prints out the ttensor.
+
ans is a ttensor of size 3 x 1 x 2
+	ans.core is a tensor of size 2 x 2 x 2
+		ans.core(:,:,1) = 
+	    0.8167    0.0174
+	    0.9855    0.8194
+		ans.core(:,:,2) = 
+	    0.6211    0.2440
+	    0.5602    0.8220
+	ans.U{1} = 
+		    0.2632    0.2141
+		    0.7536    0.6021
+		    0.6596    0.6049
+	ans.U{2} = 
+		    0.6595    0.1834
+	ans.U{3} = 
+		    0.6365    0.5396
+		    0.1703    0.6234
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/C_ttensor_doc_eq15566.png b/external/tensor_toolbox_2.5/doc/html/C_ttensor_doc_eq15566.png new file mode 100755 index 0000000000000000000000000000000000000000..34a4d34cfcaffd5b3fec11c7342e489f316f6249 GIT binary patch literal 2454 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 UE4j)+vj6}907*qoM6N<$f=~0fd;kCd literal 0 HcmV?d00001 diff --git a/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc.html b/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc.html new file mode 100755 index 0000000..9467537 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc.html @@ -0,0 +1,776 @@ + + + + + Kruskal tensors

Kruskal tensors

Kruskal format is a decomposition of a tensor X as the sum of the outer products a the columns of matrices. For example, we might write

$${\mathcal X} = \sum_r a_r \circ b_r \circ c_r$$

where a subscript denotes column index and a circle denotes outer product. In other words, the tensor X is built frm the columns of the matrices A,B, and C. It's often helpful to explicitly specify a weight for each outer product, which we do here:

$${\mathcal X} = \sum_r \lambda_r \; a_r \circ b_r \circ c_r$$

The ktensor class stores the components of the tensor X and can perform many operations, e.g., ttm, without explicitly forming the tensor X.

Contents

Kruskal tensor format via ktensor

Kruskal format stores a tensor as a sum of rank-1 outer products. For example, consider a tensor of the following form.

$$X = a_1 \circ b_1 \circ c_1 + a_2 \circ b_2 \circ c_2$$

This can be stored in Kruskal form as follows.

rand('state',0);
+A = rand(4,2); %<-- First column is a_1, second is a_2.
+B = rand(3,2); %<-- Likewise for B.
+C = rand(2,2); %<-- Likewise for C.
+X = ktensor({A,B,C}) %<-- Create the ktensor.
+
X is a ktensor of size 4 x 3 x 2
+	X.lambda = [ 1  1 ]
+	X.U{1} = 
+		    0.9501    0.8913
+		    0.2311    0.7621
+		    0.6068    0.4565
+		    0.4860    0.0185
+	X.U{2} = 
+		    0.8214    0.7919
+		    0.4447    0.9218
+		    0.6154    0.7382
+	X.U{3} = 
+		    0.1763    0.9355
+		    0.4057    0.9169
+

For Kruskal format, there can be any number of matrices, but every matrix must have the same number of columns. The number of rows can vary.

Y = ktensor({rand(4,1),rand(2,1),rand(3,1)}) %<-- Another ktensor.
+
Y is a ktensor of size 4 x 2 x 3
+	Y.lambda = [ 1 ]
+	Y.U{1} = 
+		    0.4103
+		    0.8936
+		    0.0579
+		    0.3529
+	Y.U{2} = 
+		    0.8132
+		    0.0099
+	Y.U{3} = 
+		    0.1389
+		    0.2028
+		    0.1987
+

Specifying weights in a ktensor

Weights for each rank-1 tensor can be specified by passing in a column vector. For example,

$$X = \lambda_1 \; a_1 \circ b_1 \circ c_1 + \lambda_2 \; a_2 \circ b_2 \circ c_2$$

lambda = [5.0; 0.25]; %<-- Weights for each factor.
+X = ktensor(lambda,{A,B,C}) %<-- Create the ktensor.
+
X is a ktensor of size 4 x 3 x 2
+	X.lambda = [ 5        0.25 ]
+	X.U{1} = 
+		    0.9501    0.8913
+		    0.2311    0.7621
+		    0.6068    0.4565
+		    0.4860    0.0185
+	X.U{2} = 
+		    0.8214    0.7919
+		    0.4447    0.9218
+		    0.6154    0.7382
+	X.U{3} = 
+		    0.1763    0.9355
+		    0.4057    0.9169
+

Creating a one-dimensional ktensor

Y = ktensor({rand(4,5)}) %<-- A one-dimensional ktensor.
+
Y is a ktensor of size 4
+	Y.lambda = [ 1  1  1  1  1 ]
+	Y.U{1} = 
+		    0.6038    0.7468    0.4186    0.6721    0.3795
+		    0.2722    0.4451    0.8462    0.8381    0.8318
+		    0.1988    0.9318    0.5252    0.0196    0.5028
+		    0.0153    0.4660    0.2026    0.6813    0.7095
+

Constituent parts of a ktensor

X.lambda %<-- Weights or multipliers.
+
+ans =
+
+    5.0000
+    0.2500
+
+
X.U %<-- Cell array of matrices.
+
+ans = 
+
+    [4x2 double]    [3x2 double]    [2x2 double]
+
+

Creating a ktensor from its constituent parts

Y = ktensor(X.lambda,X.U) %<-- Recreate X.
+
Y is a ktensor of size 4 x 3 x 2
+	Y.lambda = [ 5        0.25 ]
+	Y.U{1} = 
+		    0.9501    0.8913
+		    0.2311    0.7621
+		    0.6068    0.4565
+		    0.4860    0.0185
+	Y.U{2} = 
+		    0.8214    0.7919
+		    0.4447    0.9218
+		    0.6154    0.7382
+	Y.U{3} = 
+		    0.1763    0.9355
+		    0.4057    0.9169
+

Creating an empty ktensor

Z = ktensor %<-- Empty ktensor.
+
Z is a ktensor of size [empty tensor]
+	Z.lambda = [  ]
+

Use full or tensor to convert a ktensor to a tensor

full(X) %<-- Converts to a tensor.
+
ans is a tensor of size 4 x 3 x 2
+	ans(:,:,1) = 
+	    0.8529    0.5645    0.6692
+	    0.3085    0.2549    0.2569
+	    0.5239    0.3362    0.4080
+	    0.3552    0.1945    0.2668
+	ans(:,:,2) = 
+	    1.7450    1.0454    1.3370
+	    0.5235    0.3695    0.4175
+	    1.0940    0.6439    0.8348
+	    0.8131    0.4423    0.6098
+
tensor(X) %<-- Same as above.
+
ans is a tensor of size 4 x 3 x 2
+	ans(:,:,1) = 
+	    0.8529    0.5645    0.6692
+	    0.3085    0.2549    0.2569
+	    0.5239    0.3362    0.4080
+	    0.3552    0.1945    0.2668
+	ans(:,:,2) = 
+	    1.7450    1.0454    1.3370
+	    0.5235    0.3695    0.4175
+	    1.0940    0.6439    0.8348
+	    0.8131    0.4423    0.6098
+

Use double to convert a ktensor to a multidimensional array

double(X) %<-- Converts to an array.
+
+ans(:,:,1) =
+
+    0.8529    0.5645    0.6692
+    0.3085    0.2549    0.2569
+    0.5239    0.3362    0.4080
+    0.3552    0.1945    0.2668
+
+
+ans(:,:,2) =
+
+    1.7450    1.0454    1.3370
+    0.5235    0.3695    0.4175
+    1.0940    0.6439    0.8348
+    0.8131    0.4423    0.6098
+
+

Use tendiag or sptendiag to convert a ktensor to a ttensor.

A ktensor can be regarded as a ttensor with a diagonal core.

R = length(X.lambda);  %<-- Number of factors in X.
+core = tendiag(X.lambda, repmat(R,1,ndims(X))); %<-- Create a diagonal core.
+Y = ttensor(core, X.u) %<-- Assemble the ttensor.
+
Y is a ttensor of size 4 x 3 x 2
+	Y.core is a tensor of size 2 x 2 x 2
+		Y.core(:,:,1) = 
+	     5     0
+	     0     0
+		Y.core(:,:,2) = 
+	         0         0
+	         0    0.2500
+	Y.U{1} = 
+		    0.9501    0.8913
+		    0.2311    0.7621
+		    0.6068    0.4565
+		    0.4860    0.0185
+	Y.U{2} = 
+		    0.8214    0.7919
+		    0.4447    0.9218
+		    0.6154    0.7382
+	Y.U{3} = 
+		    0.1763    0.9355
+		    0.4057    0.9169
+
norm(full(X)-full(Y)) %<-- They are the same.
+
+ans =
+
+  3.8057e-016
+
+
core = sptendiag(X.lambda, repmat(R,1,ndims(X))); %<-- Sparse diagonal core.
+Y = ttensor(core, X.u) %<-- Assemble the ttensor
+
Y is a ttensor of size 4 x 3 x 2
+	Y.core is a sparse tensor of size 2 x 2 x 2 with 2 nonzeros
+	(1,1,1)    5.0000
+	(2,2,2)    0.2500
+	Y.U{1} = 
+		    0.9501    0.8913
+		    0.2311    0.7621
+		    0.6068    0.4565
+		    0.4860    0.0185
+	Y.U{2} = 
+		    0.8214    0.7919
+		    0.4447    0.9218
+		    0.6154    0.7382
+	Y.U{3} = 
+		    0.1763    0.9355
+		    0.4057    0.9169
+
norm(full(X)-full(Y)) %<-- They are the same.
+
+ans =
+
+  3.8057e-016
+
+

Use ndims and size for the dimensions of a ktensor

ndims(X) %<-- Number of dimensions.
+
+ans =
+
+     3
+
+
size(X) %<-- Row vector of the sizes.
+
+ans =
+
+     4     3     2
+
+
size(X,2) %<-- Size of the 2nd mode.
+
+ans =
+
+     3
+
+

Subscripted reference for a ktensor

X(1,1,1) %<-- Assemble the (1,1,1) element (requires computation).
+
+ans =
+
+    0.8529
+
+
X.lambda(2) %<-- Weight of 2nd factor.
+
+ans =
+
+    0.2500
+
+
X.U{2} %<-- Extract a matrix.
+
+ans =
+
+    0.8214    0.7919
+    0.4447    0.9218
+    0.6154    0.7382
+
+
X{2} %<-- Same as above.
+
+ans =
+
+    0.8214    0.7919
+    0.4447    0.9218
+    0.6154    0.7382
+
+

Subscripted assignment for a ktensor

X.lambda = ones(size(X.lambda)) %<-- Insert new multipliers.
+
X is a ktensor of size 4 x 3 x 2
+	X.lambda = [ 1  1 ]
+	X.U{1} = 
+		    0.9501    0.8913
+		    0.2311    0.7621
+		    0.6068    0.4565
+		    0.4860    0.0185
+	X.U{2} = 
+		    0.8214    0.7919
+		    0.4447    0.9218
+		    0.6154    0.7382
+	X.U{3} = 
+		    0.1763    0.9355
+		    0.4057    0.9169
+
X.lambda(1) = 7 %<-- Change a single element of lambda.
+
X is a ktensor of size 4 x 3 x 2
+	X.lambda = [ 7  1 ]
+	X.U{1} = 
+		    0.9501    0.8913
+		    0.2311    0.7621
+		    0.6068    0.4565
+		    0.4860    0.0185
+	X.U{2} = 
+		    0.8214    0.7919
+		    0.4447    0.9218
+		    0.6154    0.7382
+	X.U{3} = 
+		    0.1763    0.9355
+		    0.4057    0.9169
+
X{3}(1:2,1) = [1;1] %<-- Change the matrix for mode 3.
+
X is a ktensor of size 4 x 3 x 2
+	X.lambda = [ 7  1 ]
+	X.U{1} = 
+		    0.9501    0.8913
+		    0.2311    0.7621
+		    0.6068    0.4565
+		    0.4860    0.0185
+	X.U{2} = 
+		    0.8214    0.7919
+		    0.4447    0.9218
+		    0.6154    0.7382
+	X.U{3} = 
+		    1.0000    0.9355
+		    1.0000    0.9169
+

Use end for the last array index.

X(3:end,1,1)  %<-- Calculated X(3,1,1) and X((4,1,1).
+
+ans =
+
+    3.8274
+    2.8080
+
+
X(1,1,1:end-1)  %<-- Calculates X(1,1,1).
+
+ans =
+
+    6.1234
+
+
X{end}  %<-- Or use inside of curly braces. This is X{3}.
+
+ans =
+
+    1.0000    0.9355
+    1.0000    0.9169
+
+

Adding and subtracting ktensors

Adding two ktensors is the same as concatenating the matrices

X = ktensor({rand(4,2),rand(2,2),rand(3,2)}) %<-- Data.
+Y = ktensor({rand(4,2),rand(2,2),rand(3,2)}) %<-- More data.
+
X is a ktensor of size 4 x 2 x 3
+	X.lambda = [ 1  1 ]
+	X.U{1} = 
+		    0.4289    0.6822
+		    0.3046    0.3028
+		    0.1897    0.5417
+		    0.1934    0.1509
+	X.U{2} = 
+		    0.6979    0.8600
+		    0.3784    0.8537
+	X.U{3} = 
+		    0.5936    0.8216
+		    0.4966    0.6449
+		    0.8998    0.8180
+Y is a ktensor of size 4 x 2 x 3
+	Y.lambda = [ 1  1 ]
+	Y.U{1} = 
+		    0.6602    0.5341
+		    0.3420    0.7271
+		    0.2897    0.3093
+		    0.3412    0.8385
+	Y.U{2} = 
+		    0.5681    0.7027
+		    0.3704    0.5466
+	Y.U{3} = 
+		    0.4449    0.7948
+		    0.6946    0.9568
+		    0.6213    0.5226
+
Z = X + Y %<-- Concatenates the factor matrices.
+
Z is a ktensor of size 4 x 2 x 3
+	Z.lambda = [ 1  1  1  1 ]
+	Z.U{1} = 
+		    0.4289    0.6822    0.6602    0.5341
+		    0.3046    0.3028    0.3420    0.7271
+		    0.1897    0.5417    0.2897    0.3093
+		    0.1934    0.1509    0.3412    0.8385
+	Z.U{2} = 
+		    0.6979    0.8600    0.5681    0.7027
+		    0.3784    0.8537    0.3704    0.5466
+	Z.U{3} = 
+		    0.5936    0.8216    0.4449    0.7948
+		    0.4966    0.6449    0.6946    0.9568
+		    0.8998    0.8180    0.6213    0.5226
+
Z = X - Y %<-- Concatenates as with plus, but changes the weights.
+
Z is a ktensor of size 4 x 2 x 3
+	Z.lambda = [ 1  1 -1 -1 ]
+	Z.U{1} = 
+		    0.4289    0.6822    0.6602    0.5341
+		    0.3046    0.3028    0.3420    0.7271
+		    0.1897    0.5417    0.2897    0.3093
+		    0.1934    0.1509    0.3412    0.8385
+	Z.U{2} = 
+		    0.6979    0.8600    0.5681    0.7027
+		    0.3784    0.8537    0.3704    0.5466
+	Z.U{3} = 
+		    0.5936    0.8216    0.4449    0.7948
+		    0.4966    0.6449    0.6946    0.9568
+		    0.8998    0.8180    0.6213    0.5226
+
norm( full(Z) - (full(X)-full(Y)) ) %<-- Should be zero.
+
+ans =
+
+  1.7110e-016
+
+

Basic operations with a ktensor

+X %<-- Calls uplus.
+
ans is a ktensor of size 4 x 2 x 3
+	ans.lambda = [ 1  1 ]
+	ans.U{1} = 
+		    0.4289    0.6822
+		    0.3046    0.3028
+		    0.1897    0.5417
+		    0.1934    0.1509
+	ans.U{2} = 
+		    0.6979    0.8600
+		    0.3784    0.8537
+	ans.U{3} = 
+		    0.5936    0.8216
+		    0.4966    0.6449
+		    0.8998    0.8180
+
-X %<-- Calls uminus.
+
ans is a ktensor of size 4 x 2 x 3
+	ans.lambda = [ -1 -1 ]
+	ans.U{1} = 
+		    0.4289    0.6822
+		    0.3046    0.3028
+		    0.1897    0.5417
+		    0.1934    0.1509
+	ans.U{2} = 
+		    0.6979    0.8600
+		    0.3784    0.8537
+	ans.U{3} = 
+		    0.5936    0.8216
+		    0.4966    0.6449
+		    0.8998    0.8180
+
5*X %<-- Calls mtimes.
+
ans is a ktensor of size 4 x 2 x 3
+	ans.lambda = [ 5  5 ]
+	ans.U{1} = 
+		    0.4289    0.6822
+		    0.3046    0.3028
+		    0.1897    0.5417
+		    0.1934    0.1509
+	ans.U{2} = 
+		    0.6979    0.8600
+		    0.3784    0.8537
+	ans.U{3} = 
+		    0.5936    0.8216
+		    0.4966    0.6449
+		    0.8998    0.8180
+

Use permute to reorder the modes of a ktensor

permute(X,[2 3 1]) %<-- Reorders modes of X
+
ans is a ktensor of size 2 x 3 x 4
+	ans.lambda = [ 1  1 ]
+	ans.U{1} = 
+		    0.6979    0.8600
+		    0.3784    0.8537
+	ans.U{2} = 
+		    0.5936    0.8216
+		    0.4966    0.6449
+		    0.8998    0.8180
+	ans.U{3} = 
+		    0.4289    0.6822
+		    0.3046    0.3028
+		    0.1897    0.5417
+		    0.1934    0.1509
+

Use arrange to normalize the factors of a ktensor

The function arrange normalizes the columns of the factors and then arranges the rank-one pieces in decreasing order of size.

X = ktensor({rand(3,2),rand(4,2),rand(2,2)})  % <-- Unit weights.
+
X is a ktensor of size 3 x 4 x 2
+	X.lambda = [ 1  1 ]
+	X.U{1} = 
+		    0.8801    0.2714
+		    0.1730    0.2523
+		    0.9797    0.8757
+	X.U{2} = 
+		    0.7373    0.1991
+		    0.1365    0.2987
+		    0.0118    0.6614
+		    0.8939    0.2844
+	X.U{3} = 
+		    0.4692    0.9883
+		    0.0648    0.5828
+
arrange(X) %<-- Normalized a rearranged.
+
ans is a ktensor of size 3 x 4 x 2
+	ans.lambda = [ 0.87781     0.73416 ]
+	ans.U{1} = 
+		    0.2855    0.6626
+		    0.2653    0.1302
+		    0.9209    0.7376
+	ans.U{2} = 
+		    0.2475    0.6319
+		    0.3713    0.1170
+		    0.8221    0.0101
+		    0.3535    0.7661
+	ans.U{3} = 
+		    0.8614    0.9906
+		    0.5079    0.1368
+

Use fixsigns for sign indeterminacies in a ktensor

The largest magnitude entry for each factor is changed to be positive provided that we can flip the signs of pairs of vectors in that rank-1 component.

Y = X;
+Y.u{1}(:,1) = -Y.u{1}(:,1);  % switch the sign on a pair of columns
+Y.u{2}(:,1) = -Y.u{2}(:,1)
+
Y is a ktensor of size 3 x 4 x 2
+	Y.lambda = [ 1  1 ]
+	Y.U{1} = 
+		   -0.8801    0.2714
+		   -0.1730    0.2523
+		   -0.9797    0.8757
+	Y.U{2} = 
+		   -0.7373    0.1991
+		   -0.1365    0.2987
+		   -0.0118    0.6614
+		   -0.8939    0.2844
+	Y.U{3} = 
+		    0.4692    0.9883
+		    0.0648    0.5828
+
fixsigns(Y)
+
ans is a ktensor of size 3 x 4 x 2
+	ans.lambda = [ 1  1 ]
+	ans.U{1} = 
+		    0.8801    0.2714
+		    0.1730    0.2523
+		    0.9797    0.8757
+	ans.U{2} = 
+		    0.7373    0.1991
+		    0.1365    0.2987
+		    0.0118    0.6614
+		    0.8939    0.2844
+	ans.U{3} = 
+		    0.4692    0.9883
+		    0.0648    0.5828
+

Use ktensor to store the 'skinny' SVD of a matrix

A = rand(4,3) %<-- A random matrix.
+
+A =
+
+    0.4235    0.2259    0.6405
+    0.5155    0.5798    0.2091
+    0.3340    0.7604    0.3798
+    0.4329    0.5298    0.7833
+
+
[U,S,V] = svd(A,0); %<-- Compute the SVD.
+X = ktensor(diag(S),{U,V}) %<-- Store the SVD as a ktensor.
+
X is a ktensor of size 4 x 3
+	X.lambda = [ 1.7002     0.50951     0.22772 ]
+	X.U{1} = 
+		   -0.4346   -0.5816   -0.3635
+		   -0.4365    0.5184   -0.6947
+		   -0.5109    0.4983    0.5366
+		   -0.5996   -0.3804    0.3120
+	X.U{2} = 
+		   -0.4937    0.0444   -0.8685
+		   -0.6220    0.6800    0.3883
+		   -0.6078   -0.7319    0.3080
+
double(X) %<-- Reassemble the original matrix.
+
+ans =
+
+    0.4235    0.2259    0.6405
+    0.5155    0.5798    0.2091
+    0.3340    0.7604    0.3798
+    0.4329    0.5298    0.7833
+
+

Displaying a ktensor

disp(X) %<-- Displays the vector lambda and each factor matrix.
+
ans is a ktensor of size 4 x 3
+	ans.lambda = [ 1.7002     0.50951     0.22772 ]
+	ans.U{1} = 
+		   -0.4346   -0.5816   -0.3635
+		   -0.4365    0.5184   -0.6947
+		   -0.5109    0.4983    0.5366
+		   -0.5996   -0.3804    0.3120
+	ans.U{2} = 
+		   -0.4937    0.0444   -0.8685
+		   -0.6220    0.6800    0.3883
+		   -0.6078   -0.7319    0.3080
+

Displaying data

The datadisp function allows the user to associate meaning to the modes and display those modes with the most meaning (i.e., corresponding to the largest values).

X = ktensor({[0.8 0.1 1e-10]',[1e-5 2 3 1e-4]',[0.5 0.5]'}); %<-- Create tensor.
+X = arrange(X) %<-- Normalize the factors.
+
X is a ktensor of size 3 x 4 x 2
+	X.lambda = [ 2.0555 ]
+	X.U{1} = 
+		    0.9923
+		    0.1240
+		    0.0000
+	X.U{2} = 
+		    0.0000
+		    0.5547
+		    0.8321
+		    0.0000
+	X.U{3} = 
+		    0.7071
+		    0.7071
+
labelsDim1 = {'one','two','three'}; %<-- Labels for mode 1.
+labelsDim2 = {'A','B','C','D'}; %<-- Labels for mode 2.
+labelsDim3 = {'on','off'}; %<-- Labels for mode 3.
+datadisp(X,{labelsDim1,labelsDim2,labelsDim3}) %<-- Display.
+
+======== Group 1 ========
+
+Weight = 2.055480
+Score      Id   Name
+ 0.9922779     1 one
+ 0.1240347     2 two
+Score      Id   Name
+ 0.8320503     3 C
+ 0.5547002     2 B
+2.774e-005     4 D
+2.774e-006     1 A
+Score      Id   Name
+ 0.7071068     1 on
+ 0.7071068     2 off
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq09466.png b/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq09466.png new file mode 100755 index 0000000000000000000000000000000000000000..09db7697ee760c280088457ad6ffc60ae6290a8a GIT binary patch literal 2171 zcmV->2!!{EP)s0wJU*idhD0HB~CrwQJW*CevD`{{Mj! zvzP@<)5ne-0|11Dh0V>)!5;~}1W0R&q9BC5y}eJKJhA8bTVOVuofLTq{+3vy(NtAc zDHICUB9%&Cy?V9A36Mr3BO^XOJ^+A}l$6=o+0_jB^5x4Kr*<5_s;Vj}DXFWg3p#Tn zA%uXHpscLy!Gi|?fOqfSK?n^7!|vU?V`F32&HxpG*49>}^23J@;jh-&wbw3dO1pOL zs;#Ysze!@Y=q<4W_BMo2sZ;_0T3T8lgkxi485tQ(O-;)gEU%>2aImDjygUE^j^l6N zzJ)8Py!K@~jxaenDHIBahK5#TvPNQyYO%#)*}i?dOeRw(6e5vmU|`@EB09$D)29Id zd-v|0n3(w4;51D)Ha1G7QV8Mn^t5AV6nSQ5W^!`U+QME)rPBEL`1ba8l*lWFf)Gwl zPR`8C*rZL%)I z2M6co=Gvsk&Lx#f2L}gfn%=Ns!_lKhc|4xAe_vnU`1m+M5HDW5&}cN5FJHD94H+jU zCTePGW@l#!f{2KSNJ~qzb~YM~mo8n3iHV7hj!sWcZ*Fc*NJ#kGf!&kY+1ZwsmMvSh zT)A>($?h$ITCG+pm0ioAR4UbK^@{26=FOXp8#e*~9zA;GU>55Hfe_xhb?e-@bI7uD z=g#NPpF=wjI0~rMYKw}B(9zo1*eDi@*;{NOM#iS5rs(Ks$I--Mabsg6QmLq@NUPOa zb1N(?Jags@gm7eJ+NCb9We;s$DqoY|_S)HAoQBhGsq0ruZt5L+U0}6Zd=1l-V zet!On{^+j3U7s}%}`!^6Xlht$^A%H?thp~Yf>5Ec{^AUpci>-9pRaBy%C zLMV|)l9G}fb0{b%U_;5}a#UN;TJ(B-Y;5ev$cVk+B!*#?m6a4l-MDdM>(;IA?(QhP zaU8ez0Lo-Cola-7Py_`9rKYAr`!Bx8PSf<+vuE$zxx-omdSxKqiwVCnu96+1uO8=kqZPV+nV4bpZgv!@~gpWo2bq zSy=#pv9U2fKfmeeX+J+dk|eE{%;)oadwXMIVi1AU)KqJ3BuQ@DwvDD~f*>pw3&Sw; z^YiRV$()>=g@pyNSd0ej+qX|HmjeJMCMI}1o=t(m!@~mu1DEds!!T%__EcjS2FLN{ z=4P>2+|$#;E?`B8y}Z0UJw1`9LZJ`}gMZ*On2*$e~Fc>y(-dtK*O7!>l z^LV_pv@|a-F8~0C!x4!@LqkJTQ&VwqaW*C3a5#KEpSKKrKA*$k*pmtA`|;z)+qZ9v zM53^;Fvt3`dI11JLqoM%ZEI_*PNxeA3F+_eH&L{QUe5A3p5w@4q}?TU%RQU0q>eVMIg(MNww6IW#mhDk@4K5CjASpg1TLm&+9j zg#g(&F zLw%96*=+9U=y2eGP*YRW(9p1&fGg625MIB2eT|{m;VdzVqW(IvtRL9rmbCyvh+)|H z`1pYX2Qo7=4;?zhFpTxdv&0#d_=bjtg@uJh-R0uafv%&XqE=+P%31^fIC$_Nuyf9@ zCKUKlSO5SlF&xKjFZH)0H#e8V;h{PVxclPkNd896yQ zQ&UrUd3kEJ+Aa^0lt?5xovx*&MWs>|7Z(Qw1)&qt1q>0Kw4F}OV#N6ICBebL z002}XZ1cb{gTXLAKkwn;K~YpqO%3|U_ot^YaH_-zCX)%radc2Pu4M#4AP0tFe0+S^ z=KoKJi)!(|8Lq2z|62SfvD2|`^$srngtT5XT!8;-vD2{*S&UkXl9Cd$+3fD_{_Weh zd-v}BGx{@|Sch7Sq~!DYMx#+65EzX{*K=?s)~!%XO-+@TmtVblbzNq6CDtK}(WbtB x{aPRp000<vJR`WMcx1a002ovPDHLkV1f@97l!}< literal 0 HcmV?d00001 diff --git a/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq51104.png b/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq51104.png new file mode 100755 index 0000000000000000000000000000000000000000..e06de4143593cb1704435d52e073ccde65ad5146 GIT binary patch literal 2497 zcmV;y2|o6TP)Q010(TL_t(oh0R!5OjF$!Ugyw4kxE3-&=x3zGH4W(g2*5N3I>Zrh{oXo z5{U?ypb?BF2FDPiQ5;?zehGu7ffx{^7=@Oi21rC?s0u=~R*?$gh-GNca3A*d+>^Fc z_^)^P9-4jjS^HbxT6>?hcQ;TJMbmUwS65V2l#`Rwym|8u9z00Xv__-h@pwEQFDfdk ztE-EqX=M4o1=66=XvAW1OiT>@|Do!?02F3^em(#+H#gJ&`M`nwkdcw$<>h5EnP{3e z7z`4LM4?dpL1%v?7?LDuntt@?(dyN!na6)0)Gy3w)T>voX36|_b^Qw{(sk?B)z#I} ze{N;WBo7Aw0HA3a0FE6y_U_#~wOVa5nYM1-T2xddlgUVu1Pj=9X4M`5FbuPN^;?(` zB9iv@c8Np+0630Y^=N~^DzIOeleUVAidizxi59_3Hjd+CV`C&q1_lONzMT^lyK^Ra z|6CauhEWvd?d=^E6?NsxmD<|cyu7@`#6*gs?Ck6;hha8h)&9+!H|6E!LqkI*lWBT- z`nQS!V03hJe0&_kFt!+35kE32xidiU;~*;|g8xc&S0r=_Ls-McqFKAxf|GxrP{8ykm*hdCS$+aHEu1VIRe z!oCMf}4Gj$!E?f`_geN);IyX_d_qGv$ZPeBi(VE|;5^m$!83(tZ2(VHo!1%NK*e;Njsh`@oS+ zM@Pq(FJJh4zFaQXYPAIg1q4Cp^?E*^@8aUZSpJp@P0FQ9m!3X-x@XUx%a<=-y?Rxx zR#T$cQ=p6D=aJo zfWwCmcXoCrCnpaM4!(W+HX$LwEZ17Cc3@!Oz<~oC4(IXX#|niaD=P~bpac~c7mGxq zef#$5bh@mpETK?HlH{8=Z_L;brlzJoeE7gDh|ixtYqeU2O(YWWcsz#r;>C*|9v)Fq zQ2>yeo4aAd1^^fw98@Zm0N~)@kdcvLR+4859K~|y&YhDdPX-4Er=_J86ciK`6x_Xg zcXV`gVq!unm9AQ~ik(IqIYg84*I$3#yLZpi)3dj?7xgo2>({U6Fc|~@xm+F{9ewD~ zp`xOq%*;%IKwvgu48&rwjdf#&GiT1Yxw(0Hc>%!v`}bus8314yrqO7ss;W{`Q+<4V z7-LizhK7c+va$$*;BYvhp`pFKz24s5j7?Kh)0Qn;&;;1o*}1s5eEhk5w0HD|Fl}cr2XQw6G*RNlj zo12+p`S$HwwOS3o>Sc0rGD;eb&YOB@iGiS~`dh{qVGBPeMj-n`&$z;hd7K@ci zrBo`No}O-NYfDd0XWKM2HJv|y9snLcemp%rjf#J6Ztkg5r@&$tShHqLMMXtKM1+Hb zgHov!i^c3sx3{;K%jLScxsfDkXJ=SRxyP3z~;o)7oc7Zi? zcXx|KqP1(+0>Hq)0EfdtA46JN8i&IH0Et9`8nX;sqtO5W+JmlMy_%n&@8{mU4oy(UmmrA81NiJNt zFg7;!#EBEzwr#WAN0INixHzNHXmvNSx3@P-s8A^U^yw1-baZq8z=8z}R4Uc__3Ht^ zXf#?)>!wYc?%cWa{P}Yn$3sFwJUl#@4;=tRA`zFDSC+PZP$MrUVd^mopxHulGW{z;l8 z2Vv2oMMx5cVG4yJA|j%*vy;!~$HvA2fWcsR`SRtVLx;>p%@jBQxVpMdO-%uSN~M}V ze|}_SPB_*~Ej7B4qSj7C|#f$Rta)KcG z`}?0fd19%`cHrz886O|7tE*G1)ih04R#sXX|2Bt{laoy55gWQ-J#yp-%rx@PUcMqW ziUpdc^Yilq0s{Q~{n6QYP9E8WG);GPbwxx(2!+D^`}hAnsz1eMgBi_1SXh|9zrRc- z^Y!&@Y;2qpKNB^gLboq6nJhd!TqcvvRVri5W=l#+ii?YLbaea&>5J)KiItU300000 LNkvXXu0mjfFWkKd literal 0 HcmV?d00001 diff --git a/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq64665.png b/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq64665.png new file mode 100755 index 0000000000000000000000000000000000000000..c30747194d642d5c1ff1d51b79b77d1d3a016465 GIT binary patch literal 3448 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 S{q@|xjT~)cg{m<0!2J&=Xq`3y literal 0 HcmV?d00001 diff --git a/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq81501.png b/external/tensor_toolbox_2.5/doc/html/D_ktensor_doc_eq81501.png new file mode 100755 index 0000000000000000000000000000000000000000..90f0536f39ddbd00b523128c294525e4f69eda19 GIT binary patch literal 2517 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 + + + Multiplying tensors

Multiplying tensors

Contents

Tensor times vector (ttv for tensor)

Compute a tensor times a vector (or vectors) in one (or more) modes.

rand('state',0);
+X = tenrand([5,3,4,2]); %<-- Create a dense tensor.
+A = rand(5,1); B = rand(3,1); C = rand(4,1); D = rand(2,1); %<-- Some vectors.
+
Y = ttv(X, A, 1) %<-- X times A in mode 1.
+
Y is a tensor of size 3 x 4 x 2
+	Y(:,:,1) = 
+	    1.6875    1.9480    0.9951    0.9505
+	    0.8258    0.9495    1.4104    0.6771
+	    1.4496    0.8295    1.5943    1.6259
+	Y(:,:,2) = 
+	    1.8369    1.3352    1.0743    1.4354
+	    1.0471    1.2250    1.5317    1.2519
+	    1.4225    1.2897    1.1595    0.5775
+
Y = ttv(X, {A,B,C,D}, 1) %<-- Same as above.
+
Y is a tensor of size 3 x 4 x 2
+	Y(:,:,1) = 
+	    1.6875    1.9480    0.9951    0.9505
+	    0.8258    0.9495    1.4104    0.6771
+	    1.4496    0.8295    1.5943    1.6259
+	Y(:,:,2) = 
+	    1.8369    1.3352    1.0743    1.4354
+	    1.0471    1.2250    1.5317    1.2519
+	    1.4225    1.2897    1.1595    0.5775
+
Y = ttv(X, {A,B,C,D}, [1 2 3 4]) %<-- All-mode multiply produces a scalar.
+
+Y =
+
+    7.8707
+
+
Y = ttv(X, {D,C,B,A}, [4 3 2 1]) %<-- Same as above.
+
+Y =
+
+    7.8707
+
+
Y = ttv(X, {A,B,C,D}) %<-- Same as above.
+
+Y =
+
+    7.8707
+
+
Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4.
+
Y is a tensor of size 5 x 3
+	Y(:,:) = 
+	    1.0157    1.1081    1.5654
+	    1.3799    1.2137    1.0599
+	    1.5625    1.1830    1.0658
+	    1.2323    1.2410    1.4481
+	    1.4374    0.9573    0.8644
+
Y = ttv(X, {A,B,C,D}, [3 4]) %<-- Same as above.
+
Y is a tensor of size 5 x 3
+	Y(:,:) = 
+	    1.0157    1.1081    1.5654
+	    1.3799    1.2137    1.0599
+	    1.5625    1.1830    1.0658
+	    1.2323    1.2410    1.4481
+	    1.4374    0.9573    0.8644
+
Y = ttv(X, {A,B,D}, [1 2 4]) %<-- 3-way multiplication.
+
Y is a tensor of size 4
+	Y(:) = 
+	    4.9369
+	    4.5013
+	    4.4941
+	    3.8857
+
Y = ttv(X, {A,B,C,D}, [1 2 4]) %<-- Same as above.
+
Y is a tensor of size 4
+	Y(:) = 
+	    4.9369
+	    4.5013
+	    4.4941
+	    3.8857
+
Y = ttv(X, {A,B,D}, -3) %<-- Same as above.
+
Y is a tensor of size 4
+	Y(:) = 
+	    4.9369
+	    4.5013
+	    4.4941
+	    3.8857
+
Y = ttv(X, {A,B,C,D}, -3) %<-- Same as above.
+
Y is a tensor of size 4
+	Y(:) = 
+	    4.9369
+	    4.5013
+	    4.4941
+	    3.8857
+

Sparse tensor times vector (ttv for sptensor)

This is the same as in the dense case, except that the result may be either dense or sparse (or a scalar).

X = sptenrand([5,3,4,2],5); %<-- Create a sparse tensor.
+
Y = ttv(X, A, 1) %<-- X times A in mode 1. Result is sparse.
+
Y is a sparse tensor of size 3 x 4 x 2 with 5 nonzeros
+	(1,3,1)    0.0014
+	(2,2,1)    0.3357
+	(3,1,1)    0.5973
+	(3,1,2)    0.0005
+	(3,3,1)    0.0039
+
Y = ttv(X, {A,B,C,D}, [1 2 3 4]) %<-- All-mode multiply.
+
+Y =
+
+    0.1196
+
+
Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4.
+
Y is a sparse tensor of size 5 x 3 with 5 nonzeros
+	(2,3)    0.0009
+	(3,2)    0.0612
+	(3,3)    0.0959
+	(4,1)    0.0064
+	(4,3)    0.0149
+
Y = ttv(X, {A,B,D}, -3) %<-- 3-way multiplication. Result is *dense*!
+
Y is a tensor of size 4
+	Y(:) = 
+	    0.1512
+	    0.1064
+	    0.0014
+	         0
+

Kruskal tensor times vector (ttv for ktensor)

The special structure of a ktensor allows an efficient implementation of vector multiplication. The result is a ktensor or a scalar.

X = ktensor([10;1],rand(5,2),rand(3,2),rand(4,2),rand(2,2)); %<-- Ktensor.
+Y = ttv(X, A, 1) %<-- X times A in mode 1. Result is a ktensor.
+
Y is a ktensor of size 3 x 4 x 2
+	Y.lambda = [ 5.9997      1.1433 ]
+	Y.U{1} = 
+		    0.6927    0.4418
+		    0.0841    0.3533
+		    0.4544    0.1536
+	Y.U{2} = 
+		    0.6756    0.5548
+		    0.6992    0.1210
+		    0.7275    0.4508
+		    0.4784    0.7159
+	Y.U{3} = 
+		    0.8928    0.2548
+		    0.2731    0.8656
+
norm(full(Y) - ttv(full(X),A,1)) %<-- Result is the same as dense case.
+
+ans =
+
+  8.7990e-016
+
+
Y = ttv(X, {A,B,C,D}) %<-- All-mode multiply -- scalar result.
+
+Y =
+
+    4.8677
+
+
Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4.
+
Y is a ktensor of size 5 x 3
+	Y.lambda = [ 6.0729     0.78558 ]
+	Y.U{1} = 
+		    0.6124    0.5869
+		    0.6085    0.0576
+		    0.0158    0.3676
+		    0.0164    0.6315
+		    0.1901    0.7176
+	Y.U{2} = 
+		    0.6927    0.4418
+		    0.0841    0.3533
+		    0.4544    0.1536
+
Y = ttv(X, {A,B,D}, [1 2 4]) %<-- 3-way multiplication.
+
Y is a ktensor of size 4
+	Y.lambda = [ 3.6628     0.93892 ]
+	Y.U{1} = 
+		    0.6756    0.5548
+		    0.6992    0.1210
+		    0.7275    0.4508
+		    0.4784    0.7159
+

Tucker tensor times vector (ttv for ttensor)

The special structure of a ttensor allows an efficient implementation of vector multiplication. The result is a ttensor or a scalar.

X = ttensor(tenrand([2,2,2,2]),rand(5,2),rand(3,2),rand(4,2),rand(2,2));
+Y = ttv(X, A, 1) %<-- X times A in mode 1.
+
Y is a ttensor of size 3 x 4 x 2
+	Y.core is a tensor of size 2 x 2 x 2
+		Y.core(:,:,1) = 
+	    1.3171    0.2658
+	    1.0694    0.9612
+		Y.core(:,:,2) = 
+	    1.3377    1.4308
+	    0.3816    0.7186
+	Y.U{1} = 
+		    0.8729    0.9669
+		    0.2379    0.6649
+		    0.6458    0.8704
+	Y.U{2} = 
+		    0.0099    0.8903
+		    0.1370    0.7349
+		    0.8188    0.6873
+		    0.4302    0.3461
+	Y.U{3} = 
+		    0.1660    0.1911
+		    0.1556    0.4225
+
norm(full(Y) - ttv(full(X),A, 1)) %<-- Same as dense case.
+
+ans =
+
+  3.9154e-016
+
+
Y = ttv(X, {A,B,C,D}, [1 2 3 4]) %<-- All-mode multiply -- scalar result.
+
+Y =
+
+    3.8758
+
+
Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4.
+
Y is a ttensor of size 5 x 3
+	Y.core is a tensor of size 2 x 2
+		Y.core(:,:) = 
+	    0.6489    0.3358
+	    0.5348    0.3779
+	Y.U{1} = 
+		    0.3651    0.4586
+		    0.3932    0.8699
+		    0.5915    0.9342
+		    0.1197    0.2644
+		    0.0381    0.1603
+	Y.U{2} = 
+		    0.8729    0.9669
+		    0.2379    0.6649
+		    0.6458    0.8704
+
Y = ttv(X, {A,B,D}, [1 2 4]) %<-- 3-way multiplication.
+
Y is a ttensor of size 4
+	Y.core is a tensor of size 2
+		Y.core(:) = 
+	    2.3205
+	    2.3598
+	Y.U{1} = 
+		    0.0099    0.8903
+		    0.1370    0.7349
+		    0.8188    0.6873
+		    0.4302    0.3461
+

Tensor times matrix (ttm for tensor)

Compute a tensor times a matrix (or matrices) in one (or more) modes.

X = tensor(rand(5,3,4,2));
+A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2);
+
Y = ttm(X, A, 1);         %<-- X times A in mode-1.
+Y = ttm(X, {A,B,C,D}, 1); %<-- Same as above.
+Y = ttm(X, A', 1, 't')    %<-- Same as above.
+
Y is a tensor of size 4 x 3 x 4 x 2
+	Y(:,:,1,1) = 
+	    1.0365    0.6095    0.7110
+	    1.9302    1.4742    2.0003
+	    1.7555    1.2961    1.7017
+	    1.8896    1.4325    1.5902
+	Y(:,:,2,1) = 
+	    0.6694    0.9350    0.8098
+	    1.4311    2.0724    1.5604
+	    1.2080    1.5796    1.4965
+	    1.2773    1.7966    1.4659
+	Y(:,:,3,1) = 
+	    1.1284    1.1872    1.2511
+	    1.8427    1.8095    1.8762
+	    1.6982    1.5964    1.5908
+	    1.8864    1.8810    1.8543
+	Y(:,:,4,1) = 
+	    0.9565    1.0452    0.8766
+	    1.7992    1.8762    1.8659
+	    1.4832    1.6716    1.9043
+	    1.6718    1.8121    1.7510
+	Y(:,:,1,2) = 
+	    1.1974    0.8965    0.8668
+	    1.5665    2.1589    1.3825
+	    1.3373    2.0494    1.1534
+	    1.5943    2.0267    1.4569
+	Y(:,:,2,2) = 
+	    1.0229    1.3605    1.0827
+	    2.3149    2.1127    1.9503
+	    2.1861    1.8910    1.5869
+	    2.0542    1.9491    1.9094
+	Y(:,:,3,2) = 
+	    0.7033    0.8874    0.5347
+	    1.4749    1.4350    1.3381
+	    1.5048    1.3274    1.2796
+	    1.2465    1.5395    1.1617
+	Y(:,:,4,2) = 
+	    1.3135    0.2809    0.9096
+	    2.4720    1.0792    1.5503
+	    2.2423    0.9677    1.1401
+	    2.3171    0.8680    1.4500
+
Y = ttm(X, {A,B,C,D}, [1 2 3 4]); %<-- 4-way mutliply.
+Y = ttm(X, {D,C,B,A}, [4 3 2 1]); %<-- Same as above.
+Y = ttm(X, {A,B,C,D});            %<-- Same as above.
+Y = ttm(X, {A',B',C',D'}, 't')    %<-- Same as above.
+
Y is a tensor of size 4 x 4 x 3 x 3
+	Y(:,:,1,1) = 
+	    2.4869    4.5774    4.3080    2.4909
+	    4.7042    8.5104    8.0518    4.6694
+	    4.1588    7.5379    7.1537    4.1590
+	    4.4802    8.1581    7.6647    4.4226
+	Y(:,:,2,1) = 
+	    2.4107    4.4549    4.1826    2.4144
+	    4.8310    8.7053    8.2015    4.7393
+	    4.2267    7.6101    7.2157    4.1903
+	    4.4979    8.1691    7.6629    4.4153
+	Y(:,:,3,1) = 
+	    1.8798    3.4093    3.2097    1.8545
+	    3.3879    6.1536    5.8167    3.3717
+	    3.0143    5.4614    5.1902    3.0207
+	    3.2654    5.9270    5.5773    3.2215
+	Y(:,:,1,2) = 
+	    1.4376    2.7014    2.5398    1.4693
+	    2.7470    5.0786    4.7737    2.7583
+	    2.4439    4.5664    4.2765    2.4655
+	    2.6095    4.8234    4.5165    2.6018
+	Y(:,:,2,2) = 
+	    1.4740    2.7639    2.5977    1.5023
+	    2.8931    5.3300    4.9868    2.8703
+	    2.5479    4.7381    4.4189    2.5385
+	    2.7060    4.9891    4.6705    2.6895
+	Y(:,:,3,2) = 
+	    1.0365    1.9368    1.8275    1.0598
+	    1.9305    3.6151    3.4161    1.9837
+	    1.7213    3.2586    3.0731    1.7830
+	    1.8406    3.4297    3.2279    1.8680
+	Y(:,:,1,3) = 
+	    1.3367    2.4889    2.3411    1.3540
+	    2.5428    4.6564    4.3894    2.5403
+	    2.2559    4.1595    3.9180    2.2671
+	    2.4183    4.4405    4.1641    2.4005
+	Y(:,:,2,3) = 
+	    1.3373    2.4918    2.3410    1.3528
+	    2.6485    4.8327    4.5351    2.6148
+	    2.3258    4.2653    4.0063    2.3123
+	    2.4723    4.5286    4.2431    2.4440
+	Y(:,:,3,3) = 
+	    0.9845    1.8150    1.7108    0.9905
+	    1.8066    3.3375    3.1542    1.8302
+	    1.6093    2.9879    2.8273    1.6426
+	    1.7309    3.1876    2.9998    1.7345
+
Y = ttm(X, {C,D}, [3 4]);    %<-- X times C in mode-3 & D in mode-4
+Y = ttm(X, {A,B,C,D}, [3 4]) %<-- Same as above.
+
Y is a tensor of size 5 x 3 x 3 x 3
+	Y(:,:,1,1) = 
+	    1.5822    1.3415    1.3949
+	    1.2553    1.1977    1.2159
+	    1.4244    1.6067    1.3862
+	    1.2104    0.7492    1.5089
+	    1.2932    1.3210    1.1591
+	Y(:,:,2,1) = 
+	    1.5112    1.0441    1.3712
+	    1.1439    1.2984    1.2236
+	    1.5205    1.6549    1.5110
+	    1.3913    0.8995    1.5692
+	    1.2733    1.4256    1.0567
+	Y(:,:,3,1) = 
+	    1.0920    1.0458    1.1802
+	    0.9569    0.8498    0.8816
+	    0.9992    1.0501    0.9638
+	    0.8583    0.5944    1.0157
+	    0.9676    1.0079    0.8150
+	Y(:,:,1,2) = 
+	    0.9474    0.8303    0.7452
+	    0.8904    0.7530    0.6234
+	    0.7403    0.9461    0.8350
+	    0.8144    0.4605    0.7893
+	    0.7803    0.6910    0.7280
+	Y(:,:,2,2) = 
+	    0.9542    0.7092    0.7569
+	    0.8336    0.8635    0.6079
+	    0.8297    0.9292    0.9154
+	    0.8980    0.5883    0.7834
+	    0.8064    0.7848    0.7567
+	Y(:,:,3,2) = 
+	    0.6673    0.6108    0.5736
+	    0.6973    0.4752    0.4593
+	    0.5460    0.6273    0.5737
+	    0.5921    0.3631    0.5820
+	    0.5514    0.4938    0.5138
+	Y(:,:,1,3) = 
+	    0.8673    0.7494    0.7182
+	    0.7597    0.6751    0.6126
+	    0.7228    0.8726    0.7625
+	    0.7098    0.4168    0.7683
+	    0.7120    0.6726    0.6529
+	Y(:,:,2,3) = 
+	    0.8539    0.6157    0.7186
+	    0.7037    0.7561    0.6064
+	    0.7919    0.8754    0.8338
+	    0.7962    0.5187    0.7797
+	    0.7207    0.7460    0.6432
+	Y(:,:,3,3) = 
+	    0.6056    0.5653    0.5783
+	    0.5887    0.4485    0.4479
+	    0.5208    0.5749    0.5266
+	    0.5108    0.3295    0.5433
+	    0.5160    0.4959    0.4601
+
Y = ttm(X, {A,B,D}, [1 2 4]);   %<-- 3-way multiply.
+Y = ttm(X, {A,B,C,D}, [1 2 4]); %<-- Same as above.
+Y = ttm(X, {A,B,D}, -3);        %<-- Same as above.
+Y = ttm(X, {A,B,C,D}, -3)       %<-- Same as above.
+
Y is a tensor of size 4 x 4 x 4 x 3
+	Y(:,:,1,1) = 
+	    1.0560    2.1553    2.0387    1.1911
+	    2.4278    4.3898    4.2181    2.4754
+	    2.1441    3.9274    3.7356    2.1771
+	    2.2457    4.2196    3.9658    2.2936
+	Y(:,:,2,1) = 
+	    1.3324    2.2654    2.0972    1.1901
+	    2.6489    4.6589    4.2674    2.4065
+	    2.2210    3.9024    3.6500    2.0934
+	    2.3874    4.1487    3.8458    2.1882
+	Y(:,:,3,1) = 
+	    1.5259    2.6902    2.5346    1.4625
+	    2.4233    4.3577    4.1285    2.3958
+	    2.1583    3.9709    3.7404    2.1642
+	    2.4544    4.4132    4.1332    2.3769
+	Y(:,:,4,1) = 
+	    1.2470    2.3630    2.2327    1.2974
+	    2.4531    4.5551    4.3305    2.5251
+	    2.2263    4.0016    3.8576    2.2685
+	    2.3016    4.2637    4.0530    2.3627
+	Y(:,:,1,2) = 
+	    0.6944    1.3989    1.3155    0.7645
+	    1.4979    2.6951    2.5093    1.4364
+	    1.3402    2.4234    2.2267    1.2614
+	    1.4163    2.6071    2.4098    1.3735
+	Y(:,:,2,2) = 
+	    0.8962    1.5379    1.4173    0.8018
+	    1.6626    3.0068    2.7746    1.5774
+	    1.4220    2.6151    2.4249    1.3856
+	    1.5214    2.7047    2.5241    1.4463
+	Y(:,:,3,2) = 
+	    0.8062    1.4427    1.3306    0.7556
+	    1.3527    2.4504    2.3102    1.3362
+	    1.2317    2.2839    2.1471    1.2410
+	    1.3547    2.4308    2.2533    1.2850
+	Y(:,:,4,2) = 
+	    0.6588    1.3312    1.3007    0.7781
+	    1.3637    2.6926    2.5765    1.5156
+	    1.2072    2.3770    2.2702    1.3333
+	    1.2520    2.4805    2.3848    1.4080
+	Y(:,:,1,3) = 
+	    0.6109    1.2374    1.1665    0.6794
+	    1.3537    2.4408    2.3039    1.3333
+	    1.2045    2.1900    2.0426    1.1717
+	    1.2680    2.3547    2.1921    1.2574
+	Y(:,:,2,3) = 
+	    0.7812    1.3355    1.2330    0.6984
+	    1.4915    2.6660    2.4525    1.3896
+	    1.2650    2.2829    2.1244    1.2158
+	    1.3562    2.3881    2.2224    1.2697
+	Y(:,:,3,3) = 
+	    0.7811    1.3880    1.2929    0.7398
+	    1.2777    2.3069    2.1797    1.2626
+	    1.1519    2.1284    2.0027    1.1581
+	    1.2862    2.3100    2.1515    1.2317
+	Y(:,:,4,3) = 
+	    0.6383    1.2522    1.2053    0.7119
+	    1.2905    2.4790    2.3654    1.3861
+	    1.1555    2.1838    2.0942    1.2306
+	    1.1966    2.2999    2.2001    1.2917
+

Sparse tensor times matrix (ttm for sptensor)

It is also possible to multiply an sptensor times a matrix or series of matrices. The arguments are the same as for the dense case. The result may be dense or sparse, depending on its density.

X = sptenrand([5 3 4 2],10);
+Y = ttm(X, A, 1);         %<-- X times A in mode-1.
+Y = ttm(X, {A,B,C,D}, 1); %<-- Same as above.
+Y = ttm(X, A', 1, 't')    %<-- Same as above
+
Y is a sparse tensor of size 4 x 3 x 4 x 2 with 28 nonzeros
+	(1,1,1,1)    0.1506
+	(1,2,2,1)    0.0129
+	(1,3,2,1)    0.0893
+	(1,2,1,2)    0.4196
+	(1,1,2,2)    0.0066
+	(1,3,2,2)    0.0377
+	(1,3,3,2)    0.4310
+	(2,1,1,1)    0.7738
+	(2,2,2,1)    0.3652
+	(2,3,2,1)    0.4116
+	(2,2,1,2)    0.2315
+	(2,1,2,2)    0.1852
+	(2,3,2,2)    0.2910
+	(2,3,3,2)    0.7843
+	(3,1,1,1)    0.8920
+	(3,2,2,1)    0.2743
+	(3,3,2,1)    0.3639
+	(3,2,1,2)    0.3365
+	(3,1,2,2)    0.1391
+	(3,3,2,2)    0.2387
+	(3,3,3,2)    0.9501
+	(4,1,1,1)    0.5556
+	(4,2,2,1)    0.3154
+	(4,3,2,1)    0.1610
+	(4,2,1,2)    0.4202
+	(4,1,2,2)    0.1600
+	(4,3,2,2)    0.1799
+	(4,3,3,2)    0.7447
+
norm(full(Y) - ttm(full(X),A, 1) ) %<-- Same as dense case.
+
+ans =
+
+     0
+
+
Y = ttm(X, {A,B,C,D}, [1 2 3 4]); %<-- 4-way multiply.
+Y = ttm(X, {D,C,B,A}, [4 3 2 1]); %<-- Same as above.
+Y = ttm(X, {A,B,C,D});            %<-- Same as above.
+Y = ttm(X, {A',B',C',D'}, 't')    %<-- Same as above.
+
Y is a tensor of size 4 x 4 x 3 x 3
+	Y(:,:,1,1) = 
+	    0.0890    0.1395    0.1470    0.0913
+	    0.2458    0.5003    0.5113    0.3157
+	    0.2497    0.5323    0.5461    0.3388
+	    0.2063    0.4095    0.3985    0.2375
+	Y(:,:,2,1) = 
+	    0.0985    0.1757    0.1675    0.0976
+	    0.3510    0.7241    0.7029    0.4190
+	    0.3310    0.7403    0.7158    0.4273
+	    0.2770    0.5858    0.5249    0.2942
+	Y(:,:,3,1) = 
+	    0.0419    0.0376    0.0617    0.0462
+	    0.1291    0.1583    0.1999    0.1358
+	    0.1288    0.1546    0.2055    0.1430
+	    0.1050    0.1303    0.1583    0.1054
+	Y(:,:,1,2) = 
+	    0.0981    0.1224    0.1323    0.0821
+	    0.1729    0.2599    0.3046    0.2013
+	    0.1919    0.2865    0.3360    0.2219
+	    0.1682    0.2465    0.2699    0.1710
+	Y(:,:,2,2) = 
+	    0.0973    0.1452    0.1299    0.0708
+	    0.1977    0.3532    0.3625    0.2229
+	    0.2021    0.3706    0.3744    0.2280
+	    0.1835    0.3276    0.3052    0.1747
+	Y(:,:,3,2) = 
+	    0.0483    0.0371    0.0666    0.0510
+	    0.1054    0.0994    0.1585    0.1176
+	    0.1157    0.1031    0.1730    0.1305
+	    0.0945    0.0895    0.1386    0.1018
+	Y(:,:,1,3) = 
+	    0.0719    0.0965    0.1034    0.0642
+	    0.1480    0.2538    0.2795    0.1794
+	    0.1587    0.2752    0.3040    0.1956
+	    0.1361    0.2251    0.2346    0.1450
+	Y(:,:,2,3) = 
+	    0.0738    0.1169    0.1071    0.0599
+	    0.1860    0.3555    0.3552    0.2152
+	    0.1835    0.3684    0.3644    0.2199
+	    0.1610    0.3092    0.2830    0.1605
+	Y(:,:,3,3) = 
+	    0.0350    0.0282    0.0491    0.0374
+	    0.0853    0.0892    0.1296    0.0932
+	    0.0905    0.0902    0.1384    0.1016
+	    0.0739    0.0773    0.1094    0.0777
+
Y = ttm(X, {C,D}, [3 4]);    %<-- X times C in mode-3 & D in mode-4
+Y = ttm(X, {A,B,C,D}, [3 4]) %<-- Same as above.
+
Y is a tensor of size 5 x 3 x 3 x 3
+	Y(:,:,1,1) = 
+	         0    0.1004    0.0998
+	    0.4075         0    0.1363
+	    0.0221    0.1332    0.0167
+	         0         0    0.3307
+	         0         0         0
+	Y(:,:,2,1) = 
+	         0    0.1323    0.0395
+	    0.5371         0    0.0540
+	    0.0427    0.2578    0.0322
+	         0         0    0.6257
+	         0         0         0
+	Y(:,:,3,1) = 
+	         0    0.0154    0.0943
+	    0.0626         0    0.1289
+	    0.0123    0.0742    0.0093
+	         0         0    0.1878
+	         0         0         0
+	Y(:,:,1,2) = 
+	         0    0.1342    0.1334
+	    0.1478         0    0.1823
+	    0.0295    0.0483    0.0223
+	         0         0    0.1626
+	         0         0         0
+	Y(:,:,2,2) = 
+	         0    0.1769    0.0528
+	    0.1948         0    0.0722
+	    0.0571    0.0935    0.0431
+	         0         0    0.2955
+	         0         0         0
+	Y(:,:,3,2) = 
+	         0    0.0206    0.1262
+	    0.0227         0    0.1724
+	    0.0164    0.0269    0.0124
+	         0         0    0.0954
+	         0         0         0
+	Y(:,:,1,3) = 
+	         0    0.0933    0.0927
+	    0.1737         0    0.1267
+	    0.0205    0.0568    0.0155
+	         0         0    0.1630
+	         0         0         0
+	Y(:,:,2,3) = 
+	         0    0.1229    0.0367
+	    0.2290         0    0.0502
+	    0.0397    0.1099    0.0300
+	         0         0    0.3022
+	         0         0         0
+	Y(:,:,3,3) = 
+	         0    0.0143    0.0877
+	    0.0267         0    0.1198
+	    0.0114    0.0316    0.0086
+	         0         0    0.0942
+	         0         0         0
+
Y = ttm(X, {A,B,D}, [1 2 4]);   %<-- 3-way multiply.
+Y = ttm(X, {A,B,C,D}, [1 2 4]); %<-- Same as above.
+Y = ttm(X, {A,B,D}, -3);        %<-- Same as above.
+Y = ttm(X, {A,B,C,D}, -3)       %<-- Same as above.
+
Y is a tensor of size 4 x 4 x 4 x 3
+	Y(:,:,1,1) = 
+	    0.1010    0.2463    0.1918    0.0950
+	    0.1515    0.7021    0.6066    0.3415
+	    0.1879    0.8297    0.7130    0.3989
+	    0.1573    0.5785    0.4856    0.2645
+	Y(:,:,2,1) = 
+	    0.0416    0.0313    0.0563    0.0431
+	    0.3903    0.4667    0.4983    0.3058
+	    0.3136    0.3615    0.4026    0.2533
+	    0.2647    0.3646    0.3297    0.1801
+	Y(:,:,3,1) = 
+	    0.0468    0.0249    0.0651    0.0543
+	    0.0851    0.0453    0.1184    0.0988
+	    0.1031    0.0549    0.1434    0.1196
+	    0.0808    0.0430    0.1124    0.0938
+	Y(:,:,4,1) = 
+	     0     0     0     0
+	     0     0     0     0
+	     0     0     0     0
+	     0     0     0     0
+	Y(:,:,1,2) = 
+	    0.1147    0.2091    0.1501    0.0656
+	    0.0980    0.3207    0.2645    0.1410
+	    0.1308    0.3970    0.3232    0.1696
+	    0.1353    0.3298    0.2568    0.1271
+	Y(:,:,2,2) = 
+	    0.0194    0.0152    0.0275    0.0211
+	    0.1805    0.2340    0.2663    0.1713
+	    0.1451    0.1809    0.2133    0.1397
+	    0.1221    0.1841    0.1830    0.1087
+	Y(:,:,3,2) = 
+	    0.0626    0.0333    0.0870    0.0726
+	    0.1138    0.0606    0.1584    0.1321
+	    0.1379    0.0735    0.1919    0.1600
+	    0.1081    0.0576    0.1504    0.1254
+	Y(:,:,4,2) = 
+	     0     0     0     0
+	     0     0     0     0
+	     0     0     0     0
+	     0     0     0     0
+	Y(:,:,1,3) = 
+	    0.0834    0.1668    0.1233    0.0566
+	    0.0868    0.3335    0.2816    0.1545
+	    0.1125    0.4033    0.3373    0.1830
+	    0.1074    0.3086    0.2487    0.1289
+	Y(:,:,2,3) = 
+	    0.0200    0.0153    0.0277    0.0212
+	    0.1865    0.2324    0.2566    0.1616
+	    0.1499    0.1798    0.2064    0.1327
+	    0.1263    0.1822    0.1733    0.0992
+	Y(:,:,3,3) = 
+	    0.0435    0.0232    0.0605    0.0504
+	    0.0791    0.0421    0.1100    0.0918
+	    0.0958    0.0510    0.1333    0.1112
+	    0.0751    0.0400    0.1045    0.0872
+	Y(:,:,4,3) = 
+	     0     0     0     0
+	     0     0     0     0
+	     0     0     0     0
+	     0     0     0     0
+

The result may be dense or sparse.

X = sptenrand([5 3 4],1);
+Y = ttm(X, A, 1) %<-- Sparse result.
+
Y is a sparse tensor of size 4 x 3 x 4 with 4 nonzeros
+	(1,3,2)    0.0232
+	(2,3,2)    0.1067
+	(3,3,2)    0.0943
+	(4,3,2)    0.0417
+
X = sptenrand([5 3 4],50);
+Y = ttm(X, A, 1) %<-- Dense result.
+
Y is a tensor of size 4 x 3 x 4
+	Y(:,:,1) = 
+	    0.4159    0.5631    0.0406
+	    0.9765    1.4239    0.2088
+	    0.9029    1.2234    0.2406
+	    0.8744    1.2606    0.1499
+	Y(:,:,2) = 
+	    1.0127    0.5477         0
+	    1.4153    1.1141         0
+	    1.1989    1.0105         0
+	    1.6381    0.9835         0
+	Y(:,:,3) = 
+	    0.5923    0.6934    0.9184
+	    0.8260    0.9650    0.8641
+	    0.4955    0.7236    0.5323
+	    0.8762    0.9604    1.0351
+	Y(:,:,4) = 
+	    1.2906    0.7036    0.4899
+	    1.2638    0.8427    1.1469
+	    1.1332    0.8936    1.0464
+	    1.5305    0.9649    0.9588
+

Sometimes the product may be too large to reside in memory. For example, try the following: X = sptenrand([100 100 100 100], 1e4); A = rand(1000,100); ttm(X,A,1); %<-- too large for memory

Kruskal tensor times matrix (ttm for ktensor)

The special structure of a ktensor allows an efficient implementation of matrix multiplication. The arguments are the same as for the dense case.

X = ktensor({rand(5,1) rand(3,1) rand(4,1) rand(2,1)});
+
Y = ttm(X, A, 1);         %<-- X times A in mode-1.
+Y = ttm(X, {A,B,C,D}, 1); %<-- Same as above.
+Y = ttm(X, A', 1, 't')    %<-- Same as above.
+
Y is a ktensor of size 4 x 3 x 4 x 2
+	Y.lambda = [ 1 ]
+	Y.U{1} = 
+		    0.7712
+		    2.1158
+		    2.0046
+		    1.8224
+	Y.U{2} = 
+		    0.3790
+		    0.3373
+		    0.3146
+	Y.U{3} = 
+		    0.9471
+		    0.5352
+		    0.7020
+		    0.8750
+	Y.U{4} = 
+		    0.9862
+		    0.8853
+
Y = ttm(X, {A,B,C,D}, [1 2 3 4]); %<-- 4-way mutliply.
+Y = ttm(X, {D,C,B,A}, [4 3 2 1]); %<-- Same as above.
+Y = ttm(X, {A,B,C,D});            %<-- Same as above.
+Y = ttm(X, {A',B',C',D'}, 't')    %<-- Same as above.
+
Y is a ktensor of size 4 x 4 x 3 x 3
+	Y.lambda = [ 1 ]
+	Y.U{1} = 
+		    0.7712
+		    2.1158
+		    2.0046
+		    1.8224
+	Y.U{2} = 
+		    0.3761
+		    0.7098
+		    0.6619
+		    0.3805
+	Y.U{3} = 
+		    1.4859
+		    1.4836
+		    1.0471
+	Y.U{4} = 
+		    1.2018
+		    0.7014
+		    0.6494
+
Y = ttm(X, {C,D}, [3 4]);    %<-- X times C in mode-3 & D in mode-4.
+Y = ttm(X, {A,B,C,D}, [3 4]) %<-- Same as above.
+
Y is a ktensor of size 5 x 3 x 3 x 3
+	Y.lambda = [ 1 ]
+	Y.U{1} = 
+		    0.5430
+		    0.9035
+		    0.8613
+		    0.6315
+		    0.2624
+	Y.U{2} = 
+		    0.3790
+		    0.3373
+		    0.3146
+	Y.U{3} = 
+		    1.4859
+		    1.4836
+		    1.0471
+	Y.U{4} = 
+		    1.2018
+		    0.7014
+		    0.6494
+
Y = ttm(X, {A,B,D}, [1 2 4]);   %<-- 3-way multiply.
+Y = ttm(X, {A,B,C,D}, [1 2 4]); %<-- Same as above.
+Y = ttm(X, {A,B,D}, -3);        %<-- Same as above.
+Y = ttm(X, {A,B,C,D}, -3)       %<-- Same as above.
+
Y is a ktensor of size 4 x 4 x 4 x 3
+	Y.lambda = [ 1 ]
+	Y.U{1} = 
+		    0.7712
+		    2.1158
+		    2.0046
+		    1.8224
+	Y.U{2} = 
+		    0.3761
+		    0.7098
+		    0.6619
+		    0.3805
+	Y.U{3} = 
+		    0.9471
+		    0.5352
+		    0.7020
+		    0.8750
+	Y.U{4} = 
+		    1.2018
+		    0.7014
+		    0.6494
+

Tucker tensor times matrix (ttm for ttensor)

The special structure of a ttensor allows an efficient implementation of matrix multiplication.

X = ttensor(tensor(rand(2,2,2,2)),{rand(5,2) rand(3,2) rand(4,2) rand(2,2)});
+
Y = ttm(X, A, 1);         %<-- computes X times A in mode-1.
+Y = ttm(X, {A,B,C,D}, 1); %<-- Same as above.
+Y = ttm(X, A', 1, 't')    %<-- Same as above.
+
Y is a ttensor of size 4 x 3 x 4 x 2
+	Y.core is a tensor of size 2 x 2 x 2 x 2
+		Y.core(:,:,1,1) = 
+	    0.4048    0.3855
+	    0.6271    0.8479
+		Y.core(:,:,2,1) = 
+	    0.5268    0.3935
+	    0.8074    0.9617
+		Y.core(:,:,1,2) = 
+	    0.0301    0.7144
+	    0.9537    0.6465
+		Y.core(:,:,2,2) = 
+	    0.4467    0.8352
+	    0.1746    0.9701
+	Y.U{1} = 
+		    0.7287    1.1203
+		    1.8017    1.4937
+		    1.3952    1.1431
+		    1.5770    1.4536
+	Y.U{2} = 
+		    0.0144    0.7729
+		    0.4858    0.4881
+		    0.4164    0.5226
+	Y.U{3} = 
+		    0.7820    0.6629
+		    0.5912    0.9971
+		    0.1264    0.3462
+		    0.1097    0.1761
+	Y.U{4} = 
+		    0.0679    0.3348
+		    0.3094    0.3762
+
Y = ttm(X, {A,B,C,D}, [1 2 3 4]); %<-- 4-way multiply.
+Y = ttm(X, {D,C,B,A}, [4 3 2 1]); %<-- Same as above.
+Y = ttm(X, {A,B,C,D});            %<-- Same as above.
+Y = ttm(X, {A',B',C',D'}, 't')    %<-- Same as above.
+
Y is a ttensor of size 4 x 4 x 3 x 3
+	Y.core is a tensor of size 2 x 2 x 2 x 2
+		Y.core(:,:,1,1) = 
+	    0.4048    0.3855
+	    0.6271    0.8479
+		Y.core(:,:,2,1) = 
+	    0.5268    0.3935
+	    0.8074    0.9617
+		Y.core(:,:,1,2) = 
+	    0.0301    0.7144
+	    0.9537    0.6465
+		Y.core(:,:,2,2) = 
+	    0.4467    0.8352
+	    0.1746    0.9701
+	Y.U{1} = 
+		    0.7287    1.1203
+		    1.8017    1.4937
+		    1.3952    1.1431
+		    1.5770    1.4536
+	Y.U{2} = 
+		    0.4505    0.6010
+		    0.5530    1.2351
+		    0.5263    1.1635
+		    0.2970    0.6779
+	Y.U{3} = 
+		    0.6823    0.9247
+		    0.9196    1.1786
+		    0.2928    0.5203
+	Y.U{4} = 
+		    0.1592    0.4312
+		    0.1505    0.2692
+		    0.1157    0.2421
+
Y = ttm(X, {C,D}, [3 4]);    %<-- X times C in mode-3 & D in mode-4
+Y = ttm(X, {A,B,C,D}, [3 4]) %<-- Same as above.
+
Y is a ttensor of size 5 x 3 x 3 x 3
+	Y.core is a tensor of size 2 x 2 x 2 x 2
+		Y.core(:,:,1,1) = 
+	    0.4048    0.3855
+	    0.6271    0.8479
+		Y.core(:,:,2,1) = 
+	    0.5268    0.3935
+	    0.8074    0.9617
+		Y.core(:,:,1,2) = 
+	    0.0301    0.7144
+	    0.9537    0.6465
+		Y.core(:,:,2,2) = 
+	    0.4467    0.8352
+	    0.1746    0.9701
+	Y.U{1} = 
+		    0.1350    0.5122
+		    0.2510    0.0035
+		    0.9100    0.2269
+		    0.6765    0.9785
+		    0.6232    0.8613
+	Y.U{2} = 
+		    0.0144    0.7729
+		    0.4858    0.4881
+		    0.4164    0.5226
+	Y.U{3} = 
+		    0.6823    0.9247
+		    0.9196    1.1786
+		    0.2928    0.5203
+	Y.U{4} = 
+		    0.1592    0.4312
+		    0.1505    0.2692
+		    0.1157    0.2421
+
Y = ttm(X, {A,B,D}, [1 2 4]);   %<-- 3-way multiply
+Y = ttm(X, {A,B,C,D}, [1 2 4]); %<-- Same as above.
+Y = ttm(X, {A,B,D}, -3);        %<-- Same as above.
+Y = ttm(X, {A,B,C,D}, -3)       %<-- Same as above.
+
Y is a ttensor of size 4 x 4 x 4 x 3
+	Y.core is a tensor of size 2 x 2 x 2 x 2
+		Y.core(:,:,1,1) = 
+	    0.4048    0.3855
+	    0.6271    0.8479
+		Y.core(:,:,2,1) = 
+	    0.5268    0.3935
+	    0.8074    0.9617
+		Y.core(:,:,1,2) = 
+	    0.0301    0.7144
+	    0.9537    0.6465
+		Y.core(:,:,2,2) = 
+	    0.4467    0.8352
+	    0.1746    0.9701
+	Y.U{1} = 
+		    0.7287    1.1203
+		    1.8017    1.4937
+		    1.3952    1.1431
+		    1.5770    1.4536
+	Y.U{2} = 
+		    0.4505    0.6010
+		    0.5530    1.2351
+		    0.5263    1.1635
+		    0.2970    0.6779
+	Y.U{3} = 
+		    0.7820    0.6629
+		    0.5912    0.9971
+		    0.1264    0.3462
+		    0.1097    0.1761
+	Y.U{4} = 
+		    0.1592    0.4312
+		    0.1505    0.2692
+		    0.1157    0.2421
+

Tensor times tensor (ttt for tensor)

X = tensor(rand(4,2,3)); Y = tensor(rand(3,4,2));
+Z = ttt(X,Y); %<-- Outer product of X and Y.
+size(Z)
+
+ans =
+
+     4     2     3     3     4     2
+
+
Z = ttt(X,X,1:3) %<-- Inner product of X with itself.
+
+Z =
+
+   10.8350
+
+
Z = ttt(X,Y,[1 2 3],[2 3 1]) %<-- Inner product of X & Y.
+
+Z =
+
+    9.3217
+
+
Z = innerprod(X,Y) %<-- Same as above.
+
+Z =
+
+    8.3864
+
+
Z = ttt(X,Y,[1 3],[2 1]) %<-- Product of X & Y along specified dims.
+
Z is a tensor of size 2 x 2
+	Z(:,:) = 
+	    4.6551    3.8834
+	    4.4565    4.6666
+

Sparse tensor times sparse tensor (ttt for sptensor)

X = sptenrand([4 2 3],3); Y = sptenrand([3 4 2],3);
+Z = ttt(X,Y) %<--Outer product of X and Y.
+
Z is a sparse tensor of size 4 x 2 x 3 x 3 x 4 x 2 with 9 nonzeros
+	(1,2,1,1,1,1)    0.0241
+	(1,2,1,3,2,2)    0.0505
+	(1,2,1,3,4,2)    0.0700
+	(2,2,1,1,1,1)    0.1406
+	(2,2,1,3,2,2)    0.2947
+	(2,2,1,3,4,2)    0.4084
+	(4,2,3,1,1,1)    0.1106
+	(4,2,3,3,2,2)    0.2319
+	(4,2,3,3,4,2)    0.3214
+
norm(full(Z)-ttt(full(X),full(Y))) %<-- Same as dense.
+
+ans =
+
+     0
+
+
Z = ttt(X,X,1:3) %<-- Inner product of X with itself.
+
+Z =
+
+    0.5856
+
+
X = sptenrand([2 3],1); Y = sptenrand([3 2],1);
+Z = ttt(X, Y) %<-- Sparse result.
+
Z is a sparse tensor of size 2 x 3 x 3 x 2 with 1 nonzeros
+	(2,2,1,2)    0.2167
+
X = sptenrand([2 3],20); Y = sptenrand([3 2],20);
+Z = ttt(X, Y) %<-- Dense result.
+
Z is a tensor of size 2 x 3 x 3 x 2
+	Z(:,:,1,1) = 
+	    0.8652    0.4460    0.3551
+	    0.8837    0.6871    0.8792
+	Z(:,:,2,1) = 
+	    0.1967    0.1014    0.0807
+	    0.2009    0.1562    0.1998
+	Z(:,:,3,1) = 
+	    0.7741    0.3991    0.3177
+	    0.7907    0.6148    0.7867
+	Z(:,:,1,2) = 
+	    0.6209    0.3201    0.2549
+	    0.6343    0.4931    0.6310
+	Z(:,:,2,2) = 
+	    0.0666    0.0344    0.0274
+	    0.0681    0.0529    0.0677
+	Z(:,:,3,2) = 
+	    0.4093    0.2110    0.1680
+	    0.4181    0.3250    0.4159
+
Z = ttt(X,Y,[1 2],[2 1]) %<-- inner product of X & Y
+
+Z =
+
+    2.3874
+
+

Inner product (innerprod)

The function innerprod efficiently computes the inner product between two tensors X and Y. The code does this efficiently depending on what types of tensors X and Y.

X = tensor(rand(2,2,2))
+Y = ktensor({rand(2,2),rand(2,2),rand(2,2)})
+
X is a tensor of size 2 x 2 x 2
+	X(:,:,1) = 
+	    0.8923    0.4009
+	    0.9919    0.3407
+	X(:,:,2) = 
+	    0.3167    0.6157
+	    0.3643    0.5975
+Y is a ktensor of size 2 x 2 x 2
+	Y.lambda = [ 1  1 ]
+	Y.U{1} = 
+		    0.6852    0.2803
+		    0.9738    0.1740
+	Y.U{2} = 
+		    0.9219    0.3751
+		    0.2602    0.6447
+	Y.U{3} = 
+		    0.3165    0.2332
+		    0.1924    0.2198
+
z = innerprod(X,Y)
+
+z =
+
+    0.7764
+
+

Contraction on tensors (contract for tensor)

The function contract sums the entries of X along dimensions I and J. Contraction is a generalization of matrix trace. In other words, the trace is performed along the two-dimensional slices defined by dimensions I and J. It is possible to implement tensor multiplication as an outer product followed by a contraction.

X = sptenrand([4 3 2],5);
+Y = sptenrand([3 2 4],5);
+
Z1 = ttt(X,Y,1,3); %<-- Normal tensor multiplication
+
Z2 = contract(ttt(X,Y),1,6); %<-- Outer product + contract
+
norm(Z1-Z2) %<-- Should be zero
+
+ans =
+
+     0
+
+

Using contract on either sparse or dense tensors gives the same result

X = sptenrand([4 2 3 4],20);
+Z1 = contract(X,1,4)        % sparse version of contract
+
Z1 is a tensor of size 2 x 3
+	Z1(:,:) = 
+	         0         0    0.6799
+	    0.9183    0.1945    0.5504
+
Z2 = contract(full(X),1,4)  % dense version of contract
+
Z2 is a tensor of size 2 x 3
+	Z2(:,:) = 
+	         0         0    0.6799
+	    0.9183    0.1945    0.5504
+
norm(full(Z1) - Z2) %<-- Should be zero
+
+ans =
+
+     0
+
+

The result may be dense or sparse, depending on its density.

X = sptenrand([4 2 3 4],8);
+Y = contract(X,1,4) %<-- should be sparse
+
Y is a sparse tensor of size 2 x 3 with 2 nonzeros
+	(1,2)    0.3194
+	(2,3)    0.0341
+
X = sptenrand([4 2 3 4],80);
+Y = contract(X,1,4) %<-- should be dense
+
Y is a tensor of size 2 x 3
+	Y(:,:) = 
+	    1.9795    1.3526    1.7949
+	    0.8789    1.7861    0.2635
+

Relationships among ttv, ttm, and ttt

The three "tensor times _" functions (ttv, ttm, ttt) all perform specialized calculations, but they are all related to some degree. Here are several relationships among them:

X = tensor(rand(4,3,2));
+A = rand(4,1);
+

Tensor times vector gives a 3 x 2 result

Y1 = ttv(X,A,1)
+
Y1 is a tensor of size 3 x 2
+	Y1(:,:) = 
+	    1.3525    0.7826
+	    0.4640    0.6248
+	    0.3595    0.6841
+

When ttm is used with the transpose option, the result is almost the same as ttv

Y2 = ttm(X,A,1,'t')
+
Y2 is a tensor of size 1 x 3 x 2
+	Y2(:,:,1) = 
+	    1.3525    0.4640    0.3595
+	Y2(:,:,2) = 
+	    0.7826    0.6248    0.6841
+

We can use squeeze to remove the singleton dimension left over from ttm to give the same answer as ttv

squeeze(Y2)
+
ans is a tensor of size 3 x 2
+	ans(:,:) = 
+	    1.3525    0.7826
+	    0.4640    0.6248
+	    0.3595    0.6841
+

Tensor outer product may be used in conjuction with contract to produce the result of ttm. Please note that this is more expensive than using ttm.

Z = ttt(tensor(A),X);
+size(Z)
+
+ans =
+
+     4     1     4     3     2
+
+
Y3 = contract(Z,1,3)
+
Y3 is a tensor of size 1 x 3 x 2
+	Y3(:,:,1) = 
+	    1.3525    0.4640    0.3595
+	Y3(:,:,2) = 
+	    0.7826    0.6248    0.6841
+

Finally, use squeeze to remove the singleton dimension to get the same result as ttv.

squeeze(Y3)
+
ans is a tensor of size 3 x 2
+	ans(:,:) = 
+	    1.3525    0.7826
+	    0.4640    0.6248
+	    0.3595    0.6841
+

Frobenius norm of a tensor

The Frobenius norm of any type of tensor may be computed with the function norm. Each class is optimized to calculate the norm in the most efficient manner.

X = sptenrand([4 3 2],5)
+norm(X)
+norm(full(X))
+
X is a sparse tensor of size 4 x 3 x 2 with 5 nonzeros
+	(1,1,1)    0.4315
+	(1,3,2)    0.0963
+	(2,3,1)    0.2578
+	(3,1,2)    0.1131
+	(3,2,1)    0.1691
+
+ans =
+
+    0.5507
+
+
+ans =
+
+    0.5507
+
+
X = ktensor({rand(4,2),rand(3,2)})
+norm(X)
+
X is a ktensor of size 4 x 3
+	X.lambda = [ 1  1 ]
+	X.U{1} = 
+		    0.7782    0.7981
+		    0.5535    0.2071
+		    0.0126    0.5604
+		    0.5964    0.9688
+	X.U{2} = 
+		    0.2473    0.9360
+		    0.4601    0.0894
+		    0.6999    0.3869
+
+ans =
+
+    2.0976
+
+
X = ttensor(tensor(rand(2,2)),{rand(4,2),rand(3,2)})
+norm(X)
+
X is a ttensor of size 4 x 3
+	X.core is a tensor of size 2 x 2
+		X.core(:,:) = 
+	    0.8863    0.9777
+	    0.1854    0.6602
+	X.U{1} = 
+		    0.1073    0.6613
+		    0.3096    0.8004
+		    0.1871    0.5998
+		    0.3794    0.2723
+	X.U{2} = 
+		    0.6679    0.6879
+		    0.5256    0.1727
+		    0.1006    0.7775
+
+ans =
+
+    1.7854
+
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/N_nvecs_doc.html b/external/tensor_toolbox_2.5/doc/html/N_nvecs_doc.html new file mode 100755 index 0000000..82d4a6f --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/N_nvecs_doc.html @@ -0,0 +1,273 @@ + + + + + Generating the leading mode-n vectors

Generating the leading mode-n vectors

The leading mode-n vectors are those vectors that span the subspace of the mode-n fibers. In other words, the left singular vectors of the n-mode matricization of X.

Contents

Using nvecs to calculate the leading mode-n vectors

The nvecs command efficient computes the leading n-mode vectors.

rand('state',0);
+X = sptenrand([4,3,2],6) %<-- A sparse tensor
+
X is a sparse tensor of size 4 x 3 x 2 with 6 nonzeros
+	(1,2,1)    0.8385
+	(2,3,1)    0.5681
+	(3,2,1)    0.3704
+	(3,3,1)    0.7027
+	(4,2,2)    0.5466
+	(4,3,2)    0.4449
+
nvecs(X,1,2) %<-- The 2 leading mode-1 vectors
+
+ans =
+
+    0.5810    0.7687
+    0.3761   -0.5451
+    0.7219   -0.3347
+         0   -0.0000
+
+
nvecs(X,1,3) % <-- The 3 leading mode-1 vectors
+
+ans =
+
+    0.5810    0.7687   -0.0000
+    0.3761   -0.5451   -0.0000
+    0.7219   -0.3347    0.0000
+   -0.0000    0.0000    1.0000
+
+
nvecs(full(X),1,3) %<-- The same thing for a dense tensor
+
+ans =
+
+    0.5810    0.7687    0.0000
+    0.3761   -0.5451   -0.0000
+    0.7219   -0.3347    0.0000
+   -0.0000   -0.0000    1.0000
+
+
X = ktensor({rand(3,2),rand(3,2),rand(2,2)}) %<-- A random ktensor
+
X is a ktensor of size 3 x 3 x 2
+	X.lambda = [ 1  1 ]
+	X.U{1} = 
+		    0.1365    0.1991
+		    0.0118    0.2987
+		    0.8939    0.6614
+	X.U{2} = 
+		    0.2844    0.9883
+		    0.4692    0.5828
+		    0.0648    0.4235
+	X.U{3} = 
+		    0.5155    0.4329
+		    0.3340    0.2259
+
nvecs(X,2,1) %<-- The 1 leading mode-2 vector
+
+ans =
+
+    0.7147
+    0.6480
+    0.2633
+
+
nvecs(full(X),2,1) %<-- Same thing for a dense tensor
+
+ans =
+
+    0.7147
+    0.6480
+    0.2633
+
+
X = ttensor(tenrand([2,2,2,2]),{rand(3,2),rand(3,2),rand(2,2),rand(2,2)}); %<-- A random ttensor
+
nvecs(X,4,2) %<-- The 1 leading mode-2 vector
+
+ans =
+
+    0.6725    0.7401
+    0.7401   -0.6725
+
+
nvecs(full(X),4,2) %<-- Same thing for a dense tensor
+
+ans =
+
+    0.6725    0.7401
+    0.7401   -0.6725
+
+

Using nvecs for the HOSVD

X = tenrand([4 3 2]) %<-- Generate data
+
X is a tensor of size 4 x 3 x 2
+	X(:,:,1) = 
+	    0.0272    0.6831    0.6085
+	    0.3127    0.0928    0.0158
+	    0.0129    0.0353    0.0164
+	    0.3840    0.6124    0.1901
+	X(:,:,2) = 
+	    0.5869    0.7176    0.4418
+	    0.0576    0.6927    0.3533
+	    0.3676    0.0841    0.1536
+	    0.6315    0.4544    0.6756
+
U1 = nvecs(X,1,4); %<-- Mode 1
+U2 = nvecs(X,2,3); %<-- Mode 2
+U3 = nvecs(X,3,2); %<-- Mode 3
+S = ttm(X,{pinv(U1),pinv(U2),pinv(U3)}); %<-- Core
+Y = ttensor(S,{U1,U2,U3}) %<-- HOSVD of X
+
Y is a ttensor of size 4 x 3 x 2
+	Y.core is a tensor of size 4 x 3 x 2
+		Y.core(:,:,1) = 
+	    1.9279    0.0684   -0.0009
+	    0.0669   -0.1193   -0.1012
+	   -0.0229    0.3216    0.0848
+	    0.0013    0.0852   -0.0282
+		Y.core(:,:,2) = 
+	    0.0560   -0.2314   -0.0911
+	   -0.2194    0.5059   -0.0932
+	   -0.0393    0.0200   -0.3189
+	   -0.1786   -0.0452    0.0974
+	Y.U{1} = 
+		    0.6809   -0.4132   -0.6031    0.0424
+		    0.3358    0.8973   -0.2230    0.1799
+		    0.1548   -0.1551    0.3452    0.9126
+		    0.6321    0.0064    0.6836   -0.3647
+	Y.U{2} = 
+		    0.4538    0.8780   -0.1521
+		    0.7111   -0.4597   -0.5319
+		    0.5370   -0.1332    0.8330
+	Y.U{3} = 
+		    0.5412    0.8409
+		    0.8409   -0.5412
+
norm(full(Y) - X) %<-- Reproduces the same result.
+
+ans =
+
+  1.3020e-015
+
+
U1 = nvecs(X,1,2); %<-- Mode 1
+U2 = nvecs(X,2,2); %<-- Mode 2
+U3 = nvecs(X,3,2); %<-- Mode 3
+S = ttm(X,{pinv(U1),pinv(U2),pinv(U3)}); %<-- Core
+Y = ttensor(S,{U1,U2,U3}) %<-- Rank-(2,2,2) HOSVD approximation of X
+
Y is a ttensor of size 4 x 3 x 2
+	Y.core is a tensor of size 2 x 2 x 2
+		Y.core(:,:,1) = 
+	    1.9279    0.0684
+	    0.0669   -0.1193
+		Y.core(:,:,2) = 
+	    0.0560   -0.2314
+	   -0.2194    0.5059
+	Y.U{1} = 
+		    0.6809   -0.4132
+		    0.3358    0.8973
+		    0.1548   -0.1551
+		    0.6321    0.0064
+	Y.U{2} = 
+		    0.4538    0.8780
+		    0.7111   -0.4597
+		    0.5370   -0.1332
+	Y.U{3} = 
+		    0.5412    0.8409
+		    0.8409   -0.5412
+
100*(1-norm(full(Y)-X)/norm(X)) %<-- Percentage explained by approximation
+
+ans =
+
+   74.1571
+
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/Q_collapse_scale_doc.html b/external/tensor_toolbox_2.5/doc/html/Q_collapse_scale_doc.html new file mode 100755 index 0000000..1f3433b --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/Q_collapse_scale_doc.html @@ -0,0 +1,448 @@ + + + + + Collapsing and scaling tensors

Collapsing and scaling tensors

The tensor and sptensor classes support that notion of collapsing and scaling dimensions.

Contents

Examples of collapsing a tensor

X = tenrand([4 3 2]) %<-- Generate some data.
+
X is a tensor of size 4 x 3 x 2
+	X(:,:,1) = 
+	    0.6408    0.1708    0.3142
+	    0.1909    0.9943    0.3651
+	    0.8439    0.4398    0.3932
+	    0.1739    0.3400    0.5915
+	X(:,:,2) = 
+	    0.1197    0.9342    0.2379
+	    0.0381    0.2644    0.6458
+	    0.4586    0.1603    0.9669
+	    0.8699    0.8729    0.6649
+
Y = collapse(X,[2 3]) %<-- Sum of entries in each mode-1 slice.
+
Y is a tensor of size 4
+	Y(:) = 
+	    2.4177
+	    2.4987
+	    3.2627
+	    3.5131
+
Y = collapse(X,-1) %<-- Same as above.
+
Y is a tensor of size 4
+	Y(:) = 
+	    2.4177
+	    2.4987
+	    3.2627
+	    3.5131
+
Z = collapse(X,2) %<-- Sum of entries in each row fiber.
+
Z is a tensor of size 4 x 2
+	Z(:,:) = 
+	    1.1258    1.2919
+	    1.5503    0.9484
+	    1.6769    1.5858
+	    1.1055    2.4077
+
collapse(X,1:3) %<-- Sum of all entries.
+
+ans =
+
+   11.6922
+
+

Alternate accumulation functions for tensor

Y = collapse(X,[1 2],@max) %<-- Max entry in each mode-3 slice.
+
Y is a tensor of size 2
+	Y(:) = 
+	    0.9943
+	    0.9669
+
Z = collapse(X,-3,@mean) %<-- Average entry in each mode-3 slice.
+
Z is a tensor of size 2
+	Z(:) = 
+	    0.4549
+	    0.5195
+

Examples of collapsing a sptensor

X = sptenrand([4 3 2],6) %<-- Generate some data.
+
X is a sparse tensor of size 4 x 3 x 2 with 6 nonzeros
+	(1,2,1)    0.4507
+	(1,3,2)    0.4122
+	(2,1,1)    0.9016
+	(4,1,1)    0.0056
+	(4,1,2)    0.2974
+	(4,3,1)    0.0492
+
Y = collapse(X,[2 3]) %<-- Sum of entries in each mode-1 slice.
+
+Y =
+
+    0.8629
+    0.9016
+         0
+    0.3522
+
+
Y = collapse(X,-1) %<-- Same as above.
+
+Y =
+
+    0.8629
+    0.9016
+         0
+    0.3522
+
+
Z = collapse(X,2) %<-- Sum of entries in each row fiber.
+
Z is a sparse tensor of size 4 x 2 with 5 nonzeros
+	(1,1)    0.4507
+	(1,2)    0.4122
+	(2,1)    0.9016
+	(4,1)    0.0547
+	(4,2)    0.2974
+
collapse(X,1:3) %<-- Sum of all entries.
+
+ans =
+
+    2.1167
+
+

Alternate accumulation functions for sptensor

Y = collapse(X,[1 2],@min) %<-- Min *nonzero* entry in each mode-3 slice.
+
+Y =
+
+    0.0056
+    0.2974
+
+
Z = collapse(X,-3,@mean) %<-- Average *nonzero* entry in each mode-3 slice.
+
+Z =
+
+    0.3518
+    0.3548
+
+

Scaling a tensor in different modes

X = tenones([3,4,5]); %<-- Generate data
+S = 10 * [1:5]'; Y = scale(X,S,3) %<-- Scale in mode-3
+
Y is a tensor of size 3 x 4 x 5
+	Y(:,:,1) = 
+	    10    10    10    10
+	    10    10    10    10
+	    10    10    10    10
+	Y(:,:,2) = 
+	    20    20    20    20
+	    20    20    20    20
+	    20    20    20    20
+	Y(:,:,3) = 
+	    30    30    30    30
+	    30    30    30    30
+	    30    30    30    30
+	Y(:,:,4) = 
+	    40    40    40    40
+	    40    40    40    40
+	    40    40    40    40
+	Y(:,:,5) = 
+	    50    50    50    50
+	    50    50    50    50
+	    50    50    50    50
+
S = tensor(10 * [1:5]',5); Y = scale(X,S,3) %<-- First argument is a tensor.
+
Y is a tensor of size 3 x 4 x 5
+	Y(:,:,1) = 
+	    10    10    10    10
+	    10    10    10    10
+	    10    10    10    10
+	Y(:,:,2) = 
+	    20    20    20    20
+	    20    20    20    20
+	    20    20    20    20
+	Y(:,:,3) = 
+	    30    30    30    30
+	    30    30    30    30
+	    30    30    30    30
+	Y(:,:,4) = 
+	    40    40    40    40
+	    40    40    40    40
+	    40    40    40    40
+	Y(:,:,5) = 
+	    50    50    50    50
+	    50    50    50    50
+	    50    50    50    50
+
S = tensor(1:12,[3 4]); Y = scale(X,S,[1 2]) %<-- Scale in two modes.
+
Y is a tensor of size 3 x 4 x 5
+	Y(:,:,1) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,2) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,3) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,4) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,5) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+
S = tensor(1:12,[3 4]); Y = scale(X,S,-3) %<-- Same as above.
+
Y is a tensor of size 3 x 4 x 5
+	Y(:,:,1) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,2) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,3) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,4) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,5) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+
S = tensor(1:60,[3 4 5]); Y = scale(X,S,1:3) %<-- Scale in every mode.
+
Y is a tensor of size 3 x 4 x 5
+	Y(:,:,1) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,2) = 
+	    13    16    19    22
+	    14    17    20    23
+	    15    18    21    24
+	Y(:,:,3) = 
+	    25    28    31    34
+	    26    29    32    35
+	    27    30    33    36
+	Y(:,:,4) = 
+	    37    40    43    46
+	    38    41    44    47
+	    39    42    45    48
+	Y(:,:,5) = 
+	    49    52    55    58
+	    50    53    56    59
+	    51    54    57    60
+
Y = S .* X %<-- Same as above.
+
Y is a tensor of size 3 x 4 x 5
+	Y(:,:,1) = 
+	     1     4     7    10
+	     2     5     8    11
+	     3     6     9    12
+	Y(:,:,2) = 
+	    13    16    19    22
+	    14    17    20    23
+	    15    18    21    24
+	Y(:,:,3) = 
+	    25    28    31    34
+	    26    29    32    35
+	    27    30    33    36
+	Y(:,:,4) = 
+	    37    40    43    46
+	    38    41    44    47
+	    39    42    45    48
+	Y(:,:,5) = 
+	    49    52    55    58
+	    50    53    56    59
+	    51    54    57    60
+

Scaling a sptensor in different modes

X = ones(sptenrand([3 4 5], 10)) %<-- Generate data.
+
X is a sparse tensor of size 3 x 4 x 5 with 10 nonzeros
+	(1,2,2)     1
+	(1,4,4)     1
+	(2,1,4)     1
+	(2,3,4)     1
+	(2,4,3)     1
+	(2,4,4)     1
+	(2,4,5)     1
+	(3,2,3)     1
+	(3,3,2)     1
+	(3,4,2)     1
+
S = 10 * [1:5]'; Y = scale(X,S,3) %<-- Scale in one mode.
+
Y is a sparse tensor of size 3 x 4 x 5 with 10 nonzeros
+	(1,2,2)    20
+	(1,4,4)    40
+	(2,1,4)    40
+	(2,3,4)    40
+	(2,4,3)    30
+	(2,4,4)    40
+	(2,4,5)    50
+	(3,2,3)    30
+	(3,3,2)    20
+	(3,4,2)    20
+
S = tensor(10 * [1:5]',5); Y = scale(X,S,3) %<-- Same as above.
+
Y is a sparse tensor of size 3 x 4 x 5 with 10 nonzeros
+	(1,2,2)    20
+	(1,4,4)    40
+	(2,1,4)    40
+	(2,3,4)    40
+	(2,4,3)    30
+	(2,4,4)    40
+	(2,4,5)    50
+	(3,2,3)    30
+	(3,3,2)    20
+	(3,4,2)    20
+
S = tensor(1:12,[3 4]); Y = scale(X,S,[1 2]) %<-- Scale in two modes.
+
Y is a sparse tensor of size 3 x 4 x 5 with 10 nonzeros
+	(1,2,2)     4
+	(1,4,4)    10
+	(2,1,4)     2
+	(2,3,4)     8
+	(2,4,3)    11
+	(2,4,4)    11
+	(2,4,5)    11
+	(3,2,3)     6
+	(3,3,2)     9
+	(3,4,2)    12
+
S = tensor(1:12,[3 4]); Y = scale(X,S,-3) %<-- Same as above.
+
Y is a sparse tensor of size 3 x 4 x 5 with 10 nonzeros
+	(1,2,2)     4
+	(1,4,4)    10
+	(2,1,4)     2
+	(2,3,4)     8
+	(2,4,3)    11
+	(2,4,4)    11
+	(2,4,5)    11
+	(3,2,3)     6
+	(3,3,2)     9
+	(3,4,2)    12
+
Z = scale(X,Y,1:3) %<-- Scale by a sparse tensor.
+
Z is a sparse tensor of size 3 x 4 x 5 with 10 nonzeros
+	(1,2,2)     4
+	(1,4,4)    10
+	(2,1,4)     2
+	(2,3,4)     8
+	(2,4,3)    11
+	(2,4,4)    11
+	(2,4,5)    11
+	(3,2,3)     6
+	(3,3,2)     9
+	(3,4,2)    12
+
X .* Y %<-- Same as above.
+
ans is a sparse tensor of size 3 x 4 x 5 with 10 nonzeros
+	(1,2,2)     4
+	(1,4,4)    10
+	(2,1,4)     2
+	(2,3,4)     8
+	(2,4,3)    11
+	(2,4,4)    11
+	(2,4,5)    11
+	(3,2,3)     6
+	(3,3,2)     9
+	(3,4,2)    12
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/S_test_problems_doc.html b/external/tensor_toolbox_2.5/doc/html/S_test_problems_doc.html new file mode 100755 index 0000000..a8c15ed --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/S_test_problems_doc.html @@ -0,0 +1,682 @@ + + + + + Creating test problems and initial guesses

Creating test problems and initial guesses

We demonstrate how to use Tensor Toolbox create_problem and create_guess functions to create test problems for fitting algorithms.

Contents

Creating a CP test problem

The create_problem function allows a user to generate a test problem with a known solution having a pre-specified solution. The create_problem function generates both the solution (as a ktensor for CP) and the test data (as a tensor). We later show that a pre-specificed solution can be used as well.

% Create a problem
+info = create_problem('Size', [5 4 3], 'Num_Factors', 3, 'Noise', 0.10);
+
% Display the solution created by create_problem
+soln = info.Soln
+
soln is a ktensor of size 5 x 4 x 3
+	soln.lambda = [ 0.7764     0.48935      0.1859 ]
+	soln.U{1} = 
+		    0.5258   -1.1032   -0.1455
+		    0.1824   -1.7657    0.3118
+		    0.9157   -1.0920    2.1393
+		   -1.4192   -0.6685    0.8185
+		    0.1210   -0.5451    0.7353
+	soln.U{2} = 
+		   -1.3058    0.6887   -1.1405
+		    1.3975   -0.5577    0.2800
+		    0.8515    0.5041   -0.0953
+		   -0.2355    0.8043   -0.5103
+	soln.U{3} = 
+		   -0.7552    0.3747   -0.9519
+		    0.1934   -0.7063   -1.0122
+		   -0.1293    0.1096   -0.3956
+
% Display the data created by create_problem
+data = info.Data
+
data is a tensor of size 5 x 4 x 3
+	data(:,:,1) = 
+	    0.2167   -0.2578   -0.3358   -0.1229
+	    0.0200    0.0045   -0.2762   -0.1806
+	    0.9620   -0.8177   -0.5460    0.0604
+	   -1.0023    1.2181    0.6154   -0.2238
+	    0.1426   -0.0805   -0.1580   -0.0336
+	data(:,:,2) = 
+	    0.0905   -0.1069    0.2350    0.3185
+	    0.5405   -0.3166    0.2999    0.5282
+	    0.5628   -0.1330    0.3590    0.4859
+	    0.5634   -0.4495   -0.0716    0.2860
+	    0.3029   -0.0880    0.1421    0.1826
+	data(:,:,3) = 
+	    0.0182    0.0056   -0.1272   -0.0558
+	   -0.0347    0.0068   -0.0934   -0.0245
+	    0.2634   -0.1696   -0.0685    0.0606
+	   -0.0749    0.1920    0.1521   -0.0231
+	    0.0385    0.0496   -0.0615    0.0008
+
% The difference between true solution and measured data should match the
+% specified 10% noise.
+diff = norm(full(info.Soln) - info.Data)/norm(full(info.Soln))
+
+diff =
+
+    0.1000
+
+

Creating a Tucker test problem

The create_problem function can also be used to create Tucker problems by specifying the 'Type' as 'Tucker'. In this case, the create_problem function generates both the solution (as a ttensor for Tucker) and the test data (as a tensor).

% Create a problem
+info = create_problem('Type', 'Tucker', 'Size', [5 4 3], 'Num_Factors', [3 3 2]);
+
% Display the Tucker-type solution created by create_problem
+soln = info.Soln
+
soln is a ttensor of size 5 x 4 x 3
+	soln.core is a tensor of size 3 x 3 x 2
+		soln.core(:,:,1) = 
+	   -0.8988   -0.4175   -0.7923
+	    1.8187   -0.6114   -1.0974
+	   -0.5025   -0.8902   -1.2167
+		soln.core(:,:,2) = 
+	   -0.3826    1.8500    0.2016
+	   -1.0911   -1.5579    0.1395
+	    0.3751   -1.3389   -1.0170
+	soln.U{1} = 
+		    0.7377    0.5990    0.5210
+		   -2.7981   -0.0262    0.3796
+		   -1.1449   -0.3424   -2.1532
+		   -0.4306    0.6360    0.3872
+		    0.4012    0.7779    0.3920
+	soln.U{2} = 
+		    0.6277    0.3257    1.4809
+		   -0.4380   -0.6847   -0.3899
+		    0.3509   -0.2374   -1.4846
+		   -1.5933    2.7611    1.0004
+	soln.U{3} = 
+		   -1.0126   -0.2377
+		    0.0346    0.0114
+		    0.9299    0.2068
+
% Difference between true solution and measured data (default noise is 10%)
+diff = norm(full(info.Soln) - info.Data)/norm(full(info.Soln))
+
+diff =
+
+    0.1000
+
+

Recreating the same test problem

We can recreate exactly the same test problem when we use the same random seed and other parameters.

% Set-up, including specifying random state
+sz = [5 4 3]; %<- Size
+nf = 2; %<- Number of components
+state = RandStream.getDefaultStream.State; %<- Random state
+
% Generate first test problem
+info1 = create_problem('Size', sz, 'Num_Factors', nf, 'State', state);
+
% Generate second identical test problem
+info2 = create_problem('Size', sz, 'Num_Factors', nf, 'State', state);
+
% Check that the solutions are identical
+tf = isequal(info1.Soln, info2.Soln)
+
+tf =
+
+     1
+
+
% Check that the data are identical
+diff = norm(info1.Data - info2.Data)
+
+diff =
+
+     0
+
+

Checking default parameters and recreating the same test problem

The create_problem function returns the parameters that were used to generate it. These can be used to see the defaults. Additionally, if these are saved, they can be used to recreate the same test problems for future experiments.

% Generate test problem and use second output argument for parameters.
+[info1,params] = create_problem('Size', [5 4 3], 'Num_Factors', 2);
+
% Here are the parameters
+params
+
+params = 
+
+       Core_Generator: 'randn'
+     Factor_Generator: 'randn'
+     Lambda_Generator: 'rand'
+                    M: 0
+                Noise: 0.1000
+          Num_Factors: 2
+                 Size: [5 4 3]
+                 Soln: []
+    Sparse_Generation: 0
+             Sparse_M: 0
+                State: {1x6 cell}
+            Symmetric: []
+                 Type: 'CP'
+
+
% Recreate an identical test problem
+info2 = create_problem(params);
+
% Check that the solutions are identical
+tf = isequal(info1.Soln, info2.Soln)
+
+tf =
+
+     1
+
+
% Check that the data are identical
+diff = norm(info1.Data - info2.Data)
+
+diff =
+
+     0
+
+

Options for creating factor matrices, core tensors, and lambdas

Any function with two arguments specifying the size can be used to generate the factor matrices. This is specified by the 'Factor_Generator' option to create_problem.

Pre-defined options for 'Factor_Generator' for creating factor matrices (for CP or Tucker) include:

  • 'rand' - Uniform on [0,1]
  • 'randn' - Gaussian with mean 0 and std 1
  • 'orthogonal' - Generates a random orthogonal matrix. This option only works when the number of factors is less than or equal to the smallest dimension.
  • 'stochastic' - Generates nonnegative factor matrices so that each column sums to one.

Pre-defined options for 'Lambda_Generator' for creating lambda vector (for CP) include:

  • 'rand' - Uniform on [0,1]
  • 'randn' - Gaussian with mean 0 and std 1
  • 'orthogonal' - Creates a random vector with norm one.
  • 'stochastic' - Creates a random nonnegative vector whose entries sum to one.

Pre-defined options for 'Core_Generator' for creating core tensors (for Tucker) include:

  • 'rand' - Uniform on [0,1]
  • 'randn' - Gaussian with mean 0 and std 1
% Here is ane example of a custom factor generator
+factor_generator = @(m,n) 100*rand(m,n);
+info = create_problem('Size', [5 4 3], 'Num_Factors', 2, ...
+    'Factor_Generator', factor_generator, 'Lambda_Generator', @ones);
+first_factor_matrix = info.Soln.U{1}
+
+first_factor_matrix =
+
+   48.4964   56.6773
+   11.4613   82.3008
+   66.4856   67.3949
+   36.5374   99.9447
+   14.0044   96.1636
+
+
% Here is an example of a custom core generator for Tucker:
+info = create_problem('Type', 'Tucker', 'Size', [5 4 3], ...
+    'Num_Factors', [2 2 2], 'Core_Generator', @tenones);
+core = info.Soln.core
+
core is a tensor of size 2 x 2 x 2
+	core(:,:,1) = 
+	     1     1
+	     1     1
+	core(:,:,2) = 
+	     1     1
+	     1     1
+
% Here's another example for CP, this time using a function to create
+% factor matrices such that the inner products of the columns are
+% prespecified.
+info = create_problem('Size', [5 4 3], 'Num_Factors', 3, ...
+    'Factor_Generator', @(m,n) tt_ccong(m,n,.9));
+U = info.Soln.U{1};
+congruences = U'*U
+
+congruences =
+
+    1.0000    0.9000    0.9000
+    0.9000    1.0000    0.9000
+    0.9000    0.9000    1.0000
+
+

Generating data from an existing solution

It's possible to skip the solution generation altogether and instead just generate appropriate test data.

% Manually generate a test problem (or it comes from some
+% previous call to |create_problem|.
+soln = ktensor({rand(50,3), rand(40,3), rand(30,3)});
+
+% Use that soln to create new test problem.
+info = create_problem('Soln', soln);
+
+% Check whether solutions is equivalent to the input
+iseq = isequal(soln,info.Soln)
+
+iseq =
+
+     1
+
+

Creating dense missing data problems

It's possible to create problems that have a percentage of missing data. The problem generator randomly creates the pattern of missing data.

% Specify 25% missing data as follows:
+[info,params] = create_problem('Size', [5 4 3], 'M', 0.25);
+
% Here is the pattern of known data (1 = known, 0 = unknown)
+info.Pattern
+
ans is a tensor of size 5 x 4 x 3
+	ans(:,:,1) = 
+	     1     1     1     0
+	     1     1     1     1
+	     0     0     0     1
+	     0     1     0     1
+	     1     1     1     1
+	ans(:,:,2) = 
+	     1     1     1     1
+	     1     0     1     1
+	     1     0     0     0
+	     1     1     1     1
+	     1     1     1     1
+	ans(:,:,3) = 
+	     1     1     1     0
+	     0     1     1     1
+	     0     1     0     0
+	     1     1     1     1
+	     1     1     1     1
+
% Here is the data (incl. noise) with missing entries zeroed out
+info.Data
+
ans is a tensor of size 5 x 4 x 3
+	ans(:,:,1) = 
+	   -0.2001   -0.0428    0.0169         0
+	    0.0984    0.0376    0.0064    0.0217
+	         0         0         0   -0.1019
+	         0   -0.0470         0   -0.1454
+	   -0.2135   -0.0442    0.0256   -0.1270
+	ans(:,:,2) = 
+	   -0.0499   -0.1091    0.0518   -0.2269
+	    0.0259         0    0.0031    0.0035
+	    0.0015         0         0         0
+	    0.0505    0.0474   -0.0248    0.0934
+	   -0.0615   -0.0962    0.0362   -0.1420
+	ans(:,:,3) = 
+	    0.3410    0.0422   -0.0272         0
+	         0   -0.0425    0.0322   -0.0508
+	         0    0.0560         0         0
+	    0.6094    0.0934   -0.0624    0.2853
+	    0.3731    0.0512   -0.0468    0.1645
+

Creating sparse missing data problems.

If Sparse_M is set to true, then the data returned is sparse. Moreover, the dense versions are never explicitly created. This option only works when M >= 0.8.

% Specify 80% missing data and sparse
+info = create_problem('Size', [5 4 3], 'M', 0.80, 'Sparse_M', true);
+
% Here is the pattern of known data
+info.Pattern
+
ans is a sparse tensor of size 5 x 4 x 3 with 12 nonzeros
+	(1,3,1)     1
+	(1,4,3)     1
+	(2,2,2)     1
+	(2,3,2)     1
+	(2,4,1)     1
+	(3,1,2)     1
+	(4,1,1)     1
+	(4,2,1)     1
+	(4,4,3)     1
+	(5,1,2)     1
+	(5,2,1)     1
+	(5,2,3)     1
+
% Here is the data (incl. noise) with missing entries zeroed out
+info.Data
+
ans is a sparse tensor of size 5 x 4 x 3 with 12 nonzeros
+	(1,3,1)    0.0238
+	(1,4,3)    0.2621
+	(2,2,2)    0.0957
+	(2,3,2)   -0.0345
+	(2,4,1)    0.0449
+	(3,1,2)   -0.0623
+	(4,1,1)    0.0599
+	(4,2,1)   -0.0122
+	(4,4,3)   -0.3202
+	(5,1,2)    0.1128
+	(5,2,1)    0.0091
+	(5,2,3)   -0.6924
+

Create missing data problems with a pre-specified pattern

It's also possible to provide a specific pattern (dense or sparse) to be used to specify where data should be missing.

% Create pattern
+P = tenrand([5 4 3]) > 0.5;
+% Create test problem with that pattern
+info = create_problem('Size', size(P), 'M', P);
+% Show the data
+info.Data
+
ans is a tensor of size 5 x 4 x 3
+	ans(:,:,1) = 
+	   -0.1424         0   -0.0851    0.2725
+	         0   -0.2695         0         0
+	         0    0.8689   -0.7481    1.1611
+	         0    0.1564    0.2956         0
+	         0   -0.2786         0   -0.2237
+	ans(:,:,2) = 
+	         0   -0.3994         0   -0.6760
+	   -0.4490         0   -0.7050    0.9680
+	         0   -2.8810    1.6518         0
+	         0    0.4997    0.0797    0.2565
+	         0         0         0         0
+	ans(:,:,3) = 
+	         0         0    1.1786   -0.3976
+	         0    0.1840   -0.4430    0.3818
+	    1.1431         0         0   -1.1505
+	         0         0         0    0.1828
+	         0         0   -0.5579    0.2783
+

Creating sparse problems (CP only)

If we assume each model parameter is the input to a Poisson process, then we can generate a sparse test problems. This requires that all the factor matrices and lambda be nonnegative. The default factor generator ('randn') won't work since it produces both positive and negative values.

% Generate factor matrices with a few large entries in each column; this
+% will be the basis of our soln.
+sz = [20 15 10];
+nf = 4;
+A = cell(3,1);
+for n = 1:length(sz)
+    A{n} = rand(sz(n), nf);
+    for r = 1:nf
+        p = randperm(sz(n));
+        idx = p(1:round(.2*sz(n)));
+        A{n}(idx,r) = 10 * A{n}(idx,r);
+    end
+end
+S = ktensor(A);
+S = normalize(S,'sort',1);
+
% Create sparse test problem based on provided solution. The
+% 'Sparse_Generation' says how many insertions to make based on the
+% provided solution S. The lambda vector of the solution is automatically
+% rescaled to match the number of insertions.
+info = create_problem('Soln', S, 'Sparse_Generation', 500);
+num_nonzeros = nnz(info.Data)
+total_insertions = sum(info.Data.vals)
+orig_lambda_vs_rescaled = S.lambda ./ info.Soln.lambda
+
+num_nonzeros =
+
+   302
+
+
+total_insertions =
+
+   500
+
+
+orig_lambda_vs_rescaled =
+
+   73.8481
+   73.8481
+   73.8481
+   73.8481
+
+

Generating an initial guess

The create_guess function creates a random initial guess as a cell array of matrices. Its behavior is very similar to create_problem. A nice option is that you can generate an initial guess that is a pertubation of the solution.

info = create_problem;
+
+% Create an initial guess to go with the problem that is just a 5%
+% pertubation of the correct solution.
+U = create_guess('Soln', info.Soln, 'Factor_Generator', 'pertubation', ...
+    'Pertubation', 0.05);
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/T1_algorithms_doc.html b/external/tensor_toolbox_2.5/doc/html/T1_algorithms_doc.html new file mode 100755 index 0000000..549a45f --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/T1_algorithms_doc.html @@ -0,0 +1,449 @@ + + + + + ALS optimization for CP and Tucker tensor decompositions

ALS optimization for CP and Tucker tensor decompositions

Contents

Alternating least squares for PARAFAC/CANDECOMP

The function parafac_als computes an estimate of the best rank-R PARAFAC model of a tensor X using an alternating least-squares algorithm. The input X can be a tensor, sptensor, ktensor, or ttensor. The result P is a ktensor.

rand('state',0);
+X = sptenrand([5 4 3], 10)
+
X is a sparse tensor of size 5 x 4 x 3 with 10 nonzeros
+	(1,4,1)    0.4966
+	(2,2,3)    0.8998
+	(3,2,3)    0.8216
+	(3,3,1)    0.6449
+	(3,3,3)    0.8180
+	(3,4,1)    0.6602
+	(4,1,2)    0.3420
+	(4,1,3)    0.2897
+	(5,2,2)    0.3412
+	(5,3,2)    0.5341
+
P = parafac_als(X,2)
+
+CP_ALS:
+ Iter  1: fit = 3.219563e-001 fitdelta = 3.2e-001
+ Iter  2: fit = 3.645517e-001 fitdelta = 4.3e-002
+ Iter  3: fit = 3.732887e-001 fitdelta = 8.7e-003
+ Iter  4: fit = 3.809608e-001 fitdelta = 7.7e-003
+ Iter  5: fit = 4.021826e-001 fitdelta = 2.1e-002
+ Iter  6: fit = 4.427524e-001 fitdelta = 4.1e-002
+ Iter  7: fit = 4.734919e-001 fitdelta = 3.1e-002
+ Iter  8: fit = 4.848760e-001 fitdelta = 1.1e-002
+ Iter  9: fit = 4.890031e-001 fitdelta = 4.1e-003
+ Iter 10: fit = 4.907726e-001 fitdelta = 1.8e-003
+ Iter 11: fit = 4.916244e-001 fitdelta = 8.5e-004
+ Iter 12: fit = 4.920996e-001 fitdelta = 4.8e-004
+ Iter 13: fit = 4.924246e-001 fitdelta = 3.2e-004
+ Iter 14: fit = 4.926962e-001 fitdelta = 2.7e-004
+ Iter 15: fit = 4.929575e-001 fitdelta = 2.6e-004
+ Iter 16: fit = 4.932285e-001 fitdelta = 2.7e-004
+ Iter 17: fit = 4.935198e-001 fitdelta = 2.9e-004
+ Iter 18: fit = 4.938385e-001 fitdelta = 3.2e-004
+ Iter 19: fit = 4.941904e-001 fitdelta = 3.5e-004
+ Iter 20: fit = 4.945813e-001 fitdelta = 3.9e-004
+ Iter 21: fit = 4.950178e-001 fitdelta = 4.4e-004
+ Iter 22: fit = 4.955072e-001 fitdelta = 4.9e-004
+ Iter 23: fit = 4.960583e-001 fitdelta = 5.5e-004
+ Iter 24: fit = 4.966814e-001 fitdelta = 6.2e-004
+ Iter 25: fit = 4.973882e-001 fitdelta = 7.1e-004
+ Iter 26: fit = 4.981921e-001 fitdelta = 8.0e-004
+ Iter 27: fit = 4.991075e-001 fitdelta = 9.2e-004
+ Iter 28: fit = 5.001490e-001 fitdelta = 1.0e-003
+ Iter 29: fit = 5.013282e-001 fitdelta = 1.2e-003
+ Iter 30: fit = 5.026502e-001 fitdelta = 1.3e-003
+ Iter 31: fit = 5.041052e-001 fitdelta = 1.5e-003
+ Iter 32: fit = 5.056587e-001 fitdelta = 1.6e-003
+ Iter 33: fit = 5.072418e-001 fitdelta = 1.6e-003
+ Iter 34: fit = 5.087490e-001 fitdelta = 1.5e-003
+ Iter 35: fit = 5.100586e-001 fitdelta = 1.3e-003
+ Iter 36: fit = 5.110745e-001 fitdelta = 1.0e-003
+ Iter 37: fit = 5.117692e-001 fitdelta = 6.9e-004
+ Iter 38: fit = 5.121888e-001 fitdelta = 4.2e-004
+ Iter 39: fit = 5.124165e-001 fitdelta = 2.3e-004
+ Iter 40: fit = 5.125308e-001 fitdelta = 1.1e-004
+ Iter 41: fit = 5.125856e-001 fitdelta = 5.5e-005
+ Final fit = 5.125856e-001 
+P is a ktensor of size 5 x 4 x 3
+	P.lambda = [ 1.3189      1.1109 ]
+	P.U{1} = 
+		    0.0019    0.2743
+		    0.6406   -0.0177
+		    0.7679    0.9615
+		   -0.0000    0.0000
+		   -0.0000   -0.0000
+	P.U{2} = 
+		   -0.0000    0.0000
+		    0.9413   -0.0855
+		    0.2693    0.7083
+		   -0.2036    0.7007
+	P.U{3} = 
+		    0.0402    0.8828
+		   -0.0000   -0.0000
+		    0.9992    0.4698
+
P = parafac_als(X,2,struct('dimorder',[3 2 1]))
+
+CP_ALS:
+ Iter  1: fit = 3.575290e-001 fitdelta = 3.6e-001
+ Iter  2: fit = 4.968299e-001 fitdelta = 1.4e-001
+ Iter  3: fit = 5.047740e-001 fitdelta = 7.9e-003
+ Iter  4: fit = 5.084288e-001 fitdelta = 3.7e-003
+ Iter  5: fit = 5.103942e-001 fitdelta = 2.0e-003
+ Iter  6: fit = 5.114388e-001 fitdelta = 1.0e-003
+ Iter  7: fit = 5.119941e-001 fitdelta = 5.6e-004
+ Iter  8: fit = 5.122906e-001 fitdelta = 3.0e-004
+ Iter  9: fit = 5.124494e-001 fitdelta = 1.6e-004
+ Iter 10: fit = 5.125349e-001 fitdelta = 8.5e-005
+ Final fit = 5.125349e-001 
+P is a ktensor of size 5 x 4 x 3
+	P.lambda = [ 1.3217      1.0933 ]
+	P.U{1} = 
+		   -0.0029    0.2940
+		    0.6361   -0.0293
+		    0.7716    0.9554
+		    0.0000   -0.0000
+		    0.0000    0.0000
+	P.U{2} = 
+		    0.0000   -0.0000
+		    0.9356   -0.0865
+		    0.3018    0.6913
+		   -0.1832    0.7174
+	P.U{3} = 
+		    0.0483    0.9024
+		    0.0000    0.0000
+		    0.9988    0.4308
+
P = parafac_als(X,2,struct('dimorder',[3 2 1],'init','nvecs'))
+
+CP_ALS:
+ Iter  1: fit = 3.767513e-001 fitdelta = 3.8e-001
+ Iter  2: fit = 4.273501e-001 fitdelta = 5.1e-002
+ Iter  3: fit = 4.966758e-001 fitdelta = 6.9e-002
+ Iter  4: fit = 5.061467e-001 fitdelta = 9.5e-003
+ Iter  5: fit = 5.092466e-001 fitdelta = 3.1e-003
+ Iter  6: fit = 5.108361e-001 fitdelta = 1.6e-003
+ Iter  7: fit = 5.116747e-001 fitdelta = 8.4e-004
+ Iter  8: fit = 5.121203e-001 fitdelta = 4.5e-004
+ Iter  9: fit = 5.123582e-001 fitdelta = 2.4e-004
+ Iter 10: fit = 5.124859e-001 fitdelta = 1.3e-004
+ Iter 11: fit = 5.125545e-001 fitdelta = 6.9e-005
+ Final fit = 5.125545e-001 
+P is a ktensor of size 5 x 4 x 3
+	P.lambda = [ 1.3212      1.0943 ]
+	P.U{1} = 
+		   -0.0028    0.2928
+		    0.6367   -0.0289
+		    0.7711    0.9557
+		   -0.0000    0.0000
+		   -0.0000   -0.0000
+	P.U{2} = 
+		   -0.0000    0.0000
+		    0.9360   -0.0856
+		    0.2999    0.6927
+		   -0.1842    0.7161
+	P.U{3} = 
+		    0.0471    0.9012
+		   -0.0000   -0.0000
+		    0.9989    0.4334
+
U0 = {rand(5,2),rand(4,2),[]}; %<-- Initial guess for factors of P
+P = parafac_als(X,2,struct('dimorder',[3 2 1],'init',{U0}))
+
+CP_ALS:
+ Iter  1: fit = 4.361298e-001 fitdelta = 4.4e-001
+ Iter  2: fit = 5.082769e-001 fitdelta = 7.2e-002
+ Iter  3: fit = 5.105738e-001 fitdelta = 2.3e-003
+ Iter  4: fit = 5.116456e-001 fitdelta = 1.1e-003
+ Iter  5: fit = 5.121929e-001 fitdelta = 5.5e-004
+ Iter  6: fit = 5.124502e-001 fitdelta = 2.6e-004
+ Iter  7: fit = 5.125615e-001 fitdelta = 1.1e-004
+ Iter  8: fit = 5.126068e-001 fitdelta = 4.5e-005
+ Final fit = 5.126068e-001 
+P is a ktensor of size 5 x 4 x 3
+	P.lambda = [ 1.3217      1.1037 ]
+	P.U{1} = 
+		   -0.0007    0.2835
+		    0.6381   -0.0241
+		    0.7699    0.9587
+		    0.0000   -0.0000
+		    0.0000    0.0000
+	P.U{2} = 
+		    0.0000   -0.0000
+		    0.9388   -0.0899
+		    0.2834    0.7000
+		   -0.1957    0.7085
+	P.U{3} = 
+		    0.0487    0.8893
+		    0.0000    0.0000
+		    0.9988    0.4573
+

Alternating least squares for Tucker model

The function tucker_als computes the best rank(R1,R2,..,Rn) approximation of tensor X, according to the specified dimensions in vector R. The input X can be a tensor, sptensor, ktensor, or ttensor. The result returned in T is a ttensor.

X = sptenrand([5 4 3], 10)
+
X is a sparse tensor of size 5 x 4 x 3 with 10 nonzeros
+	(1,3,1)    0.7400
+	(3,1,2)    0.4319
+	(3,2,1)    0.6343
+	(3,3,2)    0.8030
+	(4,1,2)    0.0839
+	(4,2,1)    0.9455
+	(4,4,2)    0.9159
+	(4,4,3)    0.6020
+	(5,3,3)    0.2536
+	(5,4,3)    0.8735
+
T = tucker_als(X,2)        %<-- best rank(2,2,2) approximation
+
+Tucker Alternating Least-Squares:
+ Iter  1: fit = 2.810591e-001 fitdelta = 2.8e-001
+ Iter  2: fit = 3.474829e-001 fitdelta = 6.6e-002
+ Iter  3: fit = 3.628582e-001 fitdelta = 1.5e-002
+ Iter  4: fit = 3.700452e-001 fitdelta = 7.2e-003
+ Iter  5: fit = 3.727897e-001 fitdelta = 2.7e-003
+ Iter  6: fit = 3.737295e-001 fitdelta = 9.4e-004
+ Iter  7: fit = 3.740582e-001 fitdelta = 3.3e-004
+ Iter  8: fit = 3.741751e-001 fitdelta = 1.2e-004
+ Iter  9: fit = 3.742168e-001 fitdelta = 4.2e-005
+T is a ttensor of size 5 x 4 x 3
+	T.core is a tensor of size 2 x 2 x 2
+		T.core(:,:,1) = 
+	    1.1796   -0.0116
+	    0.4219   -0.0175
+		T.core(:,:,2) = 
+	    0.0098    1.0308
+	   -0.0191   -0.4827
+	T.U{1} = 
+		    0.0069   -0.0204
+		   -0.0000    0.0000
+		    0.2980   -0.6769
+		    0.8904   -0.0567
+		    0.3439    0.7336
+	T.U{2} = 
+		    0.0439    0.0018
+		    0.0204    0.9997
+		    0.1129    0.0109
+		    0.9924   -0.0219
+	T.U{3} = 
+		    0.0109    0.9999
+		    0.6015   -0.0016
+		    0.7988   -0.0124
+
T = tucker_als(X,[2 2 1])  %<-- best rank(2,2,1) approximation
+
+Tucker Alternating Least-Squares:
+ Iter  1: fit = 1.812756e-001 fitdelta = 1.8e-001
+ Iter  2: fit = 2.272937e-001 fitdelta = 4.6e-002
+ Iter  3: fit = 2.412379e-001 fitdelta = 1.4e-002
+ Iter  4: fit = 2.436064e-001 fitdelta = 2.4e-003
+ Iter  5: fit = 2.444688e-001 fitdelta = 8.6e-004
+ Iter  6: fit = 2.449320e-001 fitdelta = 4.6e-004
+ Iter  7: fit = 2.451964e-001 fitdelta = 2.6e-004
+ Iter  8: fit = 2.453474e-001 fitdelta = 1.5e-004
+ Iter  9: fit = 2.454331e-001 fitdelta = 8.6e-005
+T is a ttensor of size 5 x 4 x 3
+	T.core is a tensor of size 2 x 2 x 1
+		T.core(:,:,1) = 
+	    1.1975   -0.0004
+	   -0.0001    0.7710
+	T.U{1} = 
+		    0.0024    0.0387
+		   -0.0000   -0.0000
+		    0.0728    0.9885
+		    0.9137   -0.1170
+		    0.3999    0.0872
+	T.U{2} = 
+		    0.0760    0.4549
+		    0.0347    0.0306
+		    0.0869    0.8828
+		    0.9927   -0.1131
+	T.U{3} = 
+		    0.0343
+		    0.8414
+		    0.5394
+
T = tucker_als(X,2,struct('dimorder',[3 2 1]))
+
+Tucker Alternating Least-Squares:
+ Iter  1: fit = 3.268831e-001 fitdelta = 3.3e-001
+ Iter  2: fit = 3.604384e-001 fitdelta = 3.4e-002
+ Iter  3: fit = 3.708956e-001 fitdelta = 1.0e-002
+ Iter  4: fit = 3.731357e-001 fitdelta = 2.2e-003
+ Iter  5: fit = 3.738515e-001 fitdelta = 7.2e-004
+ Iter  6: fit = 3.741016e-001 fitdelta = 2.5e-004
+ Iter  7: fit = 3.741906e-001 fitdelta = 8.9e-005
+T is a ttensor of size 5 x 4 x 3
+	T.core is a tensor of size 2 x 2 x 2
+		T.core(:,:,1) = 
+	    1.1797   -0.0054
+	    0.4208   -0.0338
+		T.core(:,:,2) = 
+	    0.0015    1.0306
+	   -0.0375   -0.4818
+	T.U{1} = 
+		    0.0069   -0.0208
+		   -0.0000         0
+		    0.2981   -0.6769
+		    0.8904   -0.0566
+		    0.3439    0.7336
+	T.U{2} = 
+		    0.0440    0.0028
+		    0.0323    0.9992
+		    0.1134    0.0181
+		    0.9921   -0.0347
+	T.U{3} = 
+		    0.0298    0.9994
+		    0.6017   -0.0051
+		    0.7982   -0.0335
+
T = tucker_als(X,2,struct('dimorder',[3 2 1],'init','eigs'))
+
  Computing 2 leading e-vectors for factor 2.
+  Computing 2 leading e-vectors for factor 1.
+
+Tucker Alternating Least-Squares:
+ Iter  1: fit = 3.726300e-001 fitdelta = 3.7e-001
+ Iter  2: fit = 3.741337e-001 fitdelta = 1.5e-003
+ Iter  3: fit = 3.742335e-001 fitdelta = 1.0e-004
+T is a ttensor of size 5 x 4 x 3
+	T.core is a tensor of size 2 x 2 x 2
+		T.core(:,:,1) = 
+	    1.1798    0.0000
+	    0.4220   -0.0000
+		T.core(:,:,2) = 
+	   -0.0000    1.0311
+	   -0.0000   -0.4828
+	T.U{1} = 
+		    0.0000   -0.0000
+		    0.0000    0.0000
+		    0.2970   -0.6795
+		    0.8913   -0.0548
+		    0.3426    0.7316
+	T.U{2} = 
+		    0.0427   -0.0000
+		   -0.0000    1.0000
+		    0.1082    0.0000
+		    0.9932   -0.0000
+	T.U{3} = 
+		    0.0000    1.0000
+		    0.6045   -0.0000
+		    0.7966   -0.0000
+
U0 = {rand(5,2),rand(4,2),[]}; %<-- Initial guess for factors of T
+T = tucker_als(X,2,struct('dimorder',[3 2 1],'init',{U0}))
+
+Tucker Alternating Least-Squares:
+ Iter  1: fit = 3.647914e-001 fitdelta = 3.6e-001
+ Iter  2: fit = 3.722524e-001 fitdelta = 7.5e-003
+ Iter  3: fit = 3.735753e-001 fitdelta = 1.3e-003
+ Iter  4: fit = 3.740042e-001 fitdelta = 4.3e-004
+ Iter  5: fit = 3.741559e-001 fitdelta = 1.5e-004
+ Iter  6: fit = 3.742100e-001 fitdelta = 5.4e-005
+T is a ttensor of size 5 x 4 x 3
+	T.core is a tensor of size 2 x 2 x 2
+		T.core(:,:,1) = 
+	    1.1797   -0.0042
+	    0.4214   -0.0265
+		T.core(:,:,2) = 
+	    0.0012    1.0308
+	   -0.0293   -0.4823
+	T.U{1} = 
+		    0.0054   -0.0162
+		    0.0000    0.0000
+		    0.2980   -0.6769
+		    0.8904   -0.0567
+		    0.3439    0.7337
+	T.U{2} = 
+		    0.0440    0.0022
+		    0.0253    0.9995
+		    0.1131    0.0141
+		    0.9923   -0.0272
+	T.U{3} = 
+		    0.0233    0.9997
+		    0.6016   -0.0040
+		    0.7985   -0.0262
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/T2_opt_algorithms_doc.html b/external/tensor_toolbox_2.5/doc/html/T2_opt_algorithms_doc.html new file mode 100755 index 0000000..602a726 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/T2_opt_algorithms_doc.html @@ -0,0 +1,282 @@ + + + + + All-at-once optimization for CP tensor decomposition

All-at-once optimization for CP tensor decomposition

We explain how to use cp_opt with the POBLANO toolbox.

Contents

Poblano Optimization Toolbox

Check that you have Poblano 1.1 installed. The output of your 'ver' command should look something like the following.

ver
+
-------------------------------------------------------------------------------------
+MATLAB Version 7.13.0.564 (R2011b)
+MATLAB License Number: 192525
+Operating System: Microsoft Windows 7 Version 6.1 (Build 7600)
+Java VM Version: Java 1.6.0_17-b04 with Sun Microsystems Inc. Java HotSpot(TM) 64-Bit Server VM mixed mode
+-------------------------------------------------------------------------------------
+MATLAB                                                Version 7.13       (R2011b)
+Poblano Toolbox (Sandia National Labs)                Version 1.1                
+Statistics Toolbox                                    Version 7.6        (R2011b)
+Tensor Toolbox (Sandia National Labs)                 Version 2.5                
+

Create an example problem. Here we have 10% noise.

R = 5;
+info = create_problem('Size', [50 40 30], 'Num_Factors', R, 'Noise', 0.10);
+X = info.Data;
+M_true= info.Soln;
+

Create initial guess using 'nvecs'

M_init = create_guess('Data', X, 'Num_Factors', R, ...
+    'Factor_Generator', 'nvecs');
+

Set up the optimization parameters

It's genearlly a good idea to consider the parameters of the optimization method. The default options may be either too stringent or not stringent enough. The most important options to consider are detailed here.

% Get the defaults
+ncg_opts = ncg('defaults');
+% Tighten the stop tolerance (norm of gradient). This is often too large.
+ncg_opts.StopTol = 1.0e-6;
+% Tighten relative change in function value tolearnce. This is often too large.
+ncg_opts.RelFuncTol = 1.0e-20;
+% Increase the number of iterations.
+ncg_opts.MaxIters = 10^4;
+% Only display every 10th iteration
+ncg_opts.DisplayIters = 10;
+% Display the final set of options
+ncg_opts
+
+ncg_opts = 
+
+                   Display: 'iter'
+              DisplayIters: 10
+           LineSearch_ftol: 1.0000e-004
+           LineSearch_gtol: 0.0100
+    LineSearch_initialstep: 1
+         LineSearch_maxfev: 20
+         LineSearch_method: 'more-thuente'
+         LineSearch_stpmax: 1.0000e+015
+         LineSearch_stpmin: 1.0000e-015
+           LineSearch_xtol: 1.0000e-015
+              MaxFuncEvals: 10000
+                  MaxIters: 10000
+                RelFuncTol: 1.0000e-020
+              RestartIters: 20
+                 RestartNW: 0
+              RestartNWTol: 0.1000
+                   StopTol: 1.0000e-006
+                 TraceFunc: 0
+            TraceFuncEvals: 0
+                 TraceGrad: 0
+             TraceGradNorm: 0
+              TraceRelFunc: 0
+                    TraceX: 0
+                    Update: 'PR'
+
+

Call the cp_opt method

Here is an example call to the cp_opt method. By default, each iteration prints the least squares fit function value (being minimized) and the norm of the gradient. The meaning of any line search warnings can be checked via doc cvsrch.

[M,~,output] = cp_opt(X, R, 'init', M_init, ...
+    'alg', 'ncg', 'alg_options', ncg_opts);
+
 Iter  FuncEvals       F(X)          ||G(X)||/N        
+------ --------- ---------------- ----------------
+     0         1   75593.24987686       0.70699321
+    10        83     833.36966011       0.82018460
+    20       131     742.99421395       0.01035414
+    30       158     742.97545770       0.00016140
+    40       178     742.97544883       0.00000137
+    42       182     742.97544883       0.00000093
+

Check the output

It's important to check the output of the optimization method. In particular, it's worthwhile to check the exit flag. A zero (0) indicates successful termination with the gradient smaller than the specified StopTol, and a three (3) indicates a successful termination where the change in function value is less than RelFuncTol. The meaning of any other flags can be checked via doc poblano_params.

exitflag = output.ExitFlag
+
+exitflag =
+
+     0
+
+

The fit is the percentage of the data that is explained by the model. Because we have noise, we do not expect the fit to be perfect.

fit = output.Fit
+
+fit =
+
+   99.0203
+
+

Evaluate the output

We can "score" the similarity of the model computed by CP and compare that with the truth. The score function on ktensor's gives a score in [0,1] with 1 indicating a perfect match. Because we have noise, we do not expect the fit to be perfect. See doc score for more details.

scr = score(M,M_true)
+
+scr =
+
+    0.9986
+
+

Overfitting example

Consider the case where we don't know R in advance. We might guess too high. Here we show a case where we guess R+1 factors rather than R.

% Generate initial guess of the corret size
+M_plus_init = create_guess('Data', X, 'Num_Factors', R+1, ...
+    'Factor_Generator', 'nvecs');
+
% Loosen the stop tolerance (norm of gradient).
+ncg_opts.StopTol = 1.0e-2;
+
% Run the algorithm
+[M_plus,~,output] = cp_opt(X, R+1, 'init', M_plus_init, ...
+    'alg', 'ncg', 'alg_options', ncg_opts);
+exitflag = output.ExitFlag
+fit = output.Fit
+
 Iter  FuncEvals       F(X)          ||G(X)||/N        
+------ --------- ---------------- ----------------
+     0         1   75593.78388667       0.58917501
+    10        83     833.52870514       0.68349823
+    20       131     743.08624109       0.00959787
+
+exitflag =
+
+     0
+
+
+fit =
+
+   99.0201
+
+
% Check the answer (1 is perfect)
+scr = score(M_plus, M_true)
+
+scr =
+
+    0.9984
+
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/T3_wopt_algorithms_doc.html b/external/tensor_toolbox_2.5/doc/html/T3_wopt_algorithms_doc.html new file mode 100755 index 0000000..002727d --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/T3_wopt_algorithms_doc.html @@ -0,0 +1,354 @@ + + + + + Weighted optimization for CP tensor decomposition with incomplete data

Weighted optimization for CP tensor decomposition with incomplete data

We explain how to use cp_wopt with the POBLANO toolbox.

Contents

Create an example problem with missing data.

Here we have 25% missing data and 10% noise.

R = 2;
+info = create_problem('Size', [15 10 5], 'Num_Factors', R, ...
+    'M', 0.25, 'Noise', 0.10);
+X = info.Data;
+P = info.Pattern;
+M_true= info.Soln;
+

Create initial guess using 'nvecs'

M_init = create_guess('Data', X, 'Num_Factors', R, ...
+    'Factor_Generator', 'nvecs');
+

Set up the optimization parameters

It's genearlly a good idea to consider the parameters of the optimization method. The default options may be either too stringent or not stringent enough. The most important options to consider are detailed here.

% Get the defaults
+ncg_opts = ncg('defaults');
+% Tighten the stop tolerance (norm of gradient). This is often too large.
+ncg_opts.StopTol = 1.0e-6;
+% Tighten relative change in function value tolearnce. This is often too large.
+ncg_opts.RelFuncTol = 1.0e-20;
+% Increase the number of iterations.
+ncg_opts.MaxIters = 10^4;
+% Only display every 10th iteration
+ncg_opts.DisplayIters = 10;
+% Display the final set of options
+ncg_opts
+
+ncg_opts = 
+
+                   Display: 'iter'
+              DisplayIters: 10
+           LineSearch_ftol: 1.0000e-004
+           LineSearch_gtol: 0.0100
+    LineSearch_initialstep: 1
+         LineSearch_maxfev: 20
+         LineSearch_method: 'more-thuente'
+         LineSearch_stpmax: 1.0000e+015
+         LineSearch_stpmin: 1.0000e-015
+           LineSearch_xtol: 1.0000e-015
+              MaxFuncEvals: 10000
+                  MaxIters: 10000
+                RelFuncTol: 1.0000e-020
+              RestartIters: 20
+                 RestartNW: 0
+              RestartNWTol: 0.1000
+                   StopTol: 1.0000e-006
+                 TraceFunc: 0
+            TraceFuncEvals: 0
+                 TraceGrad: 0
+             TraceGradNorm: 0
+              TraceRelFunc: 0
+                    TraceX: 0
+                    Update: 'PR'
+
+

Call the cp_wopt method

Here is an example call to the cp_opt method. By default, each iteration prints the least squares fit function value (being minimized) and the norm of the gradient. The meaning of any line search warnings can be checked via doc cvsrch.

[M,~,output] = cp_wopt(X, P, R, 'init', M_init, ...
+    'alg', 'ncg', 'alg_options', ncg_opts);
+
 Iter  FuncEvals       F(X)          ||G(X)||/N        
+------ --------- ---------------- ----------------
+     0         1      38.81030020       0.21627555
+    10        43       0.48416976       0.01540206
+    20        68       0.41476299       0.00074832
+    30        88       0.41463604       0.00005718
+    40       108       0.41463533       0.00000281
+    46       120       0.41463533       0.00000084
+

Check the output

It's important to check the output of the optimization method. In particular, it's worthwhile to check the exit flag. A zero (0) indicates successful termination with the gradient smaller than the specified StopTol, and a three (3) indicates a successful termination where the change in function value is less than RelFuncTol. The meaning of any other flags can be checked via doc poblano_params.

exitflag = output.ExitFlag
+
+exitflag =
+
+     0
+
+

Evaluate the output

We can "score" the similarity of the model computed by CP and compare that with the truth. The score function on ktensor's gives a score in [0,1] with 1 indicating a perfect match. Because we have noise, we do not expect the fit to be perfect. See doc score for more details.

scr = score(M,M_true)
+
+scr =
+
+    0.9946
+
+

Create a SPARSE example problem with missing data.

Here we have 95% missing data and 10% noise.

R = 2;
+info = create_problem('Size', [150 100 50], 'Num_Factors', R, ...
+    'M', 0.95, 'Sparse_M', true, 'Noise', 0.10);
+X = info.Data;
+P = info.Pattern;
+M_true= info.Soln;
+

Create initial guess using 'nvecs'

M_init = create_guess('Data', X, 'Num_Factors', R, ...
+    'Factor_Generator', 'nvecs');
+

Set up the optimization parameters

It's genearlly a good idea to consider the parameters of the optimization method. The default options may be either too stringent or not stringent enough. The most important options to consider are detailed here.

% Get the defaults
+ncg_opts = ncg('defaults');
+% Tighten the stop tolerance (norm of gradient). This is often too large.
+ncg_opts.StopTol = 1.0e-6;
+% Tighten relative change in function value tolearnce. This is often too large.
+ncg_opts.RelFuncTol = 1.0e-20;
+% Increase the number of iterations.
+ncg_opts.MaxIters = 10^4;
+% Only display every 10th iteration
+ncg_opts.DisplayIters = 10;
+% Display the final set of options
+ncg_opts
+
+ncg_opts = 
+
+                   Display: 'iter'
+              DisplayIters: 10
+           LineSearch_ftol: 1.0000e-004
+           LineSearch_gtol: 0.0100
+    LineSearch_initialstep: 1
+         LineSearch_maxfev: 20
+         LineSearch_method: 'more-thuente'
+         LineSearch_stpmax: 1.0000e+015
+         LineSearch_stpmin: 1.0000e-015
+           LineSearch_xtol: 1.0000e-015
+              MaxFuncEvals: 10000
+                  MaxIters: 10000
+                RelFuncTol: 1.0000e-020
+              RestartIters: 20
+                 RestartNW: 0
+              RestartNWTol: 0.1000
+                   StopTol: 1.0000e-006
+                 TraceFunc: 0
+            TraceFuncEvals: 0
+                 TraceGrad: 0
+             TraceGradNorm: 0
+              TraceRelFunc: 0
+                    TraceX: 0
+                    Update: 'PR'
+
+

Call the cp_wopt method

Here is an example call to the cp_opt method. By default, each iteration prints the least squares fit function value (being minimized) and the norm of the gradient. The meaning of any line search warnings can be checked via doc cvsrch.

[M,~,output] = cp_wopt(X, P, R, 'init', M_init, ...
+    'alg', 'ncg', 'alg_options', ncg_opts);
+
 Iter  FuncEvals       F(X)          ||G(X)||/N        
+------ --------- ---------------- ----------------
+     0         1    1379.93609993       0.02752852
+    10        58     132.46275289       0.01902211
+    20        90     128.70825353       0.00582068
+    30       129     126.41868561       0.01373756
+    40       170     119.98598848       0.00928409
+    50       207     117.10117490       0.01090024
+    60       245     114.67006514       0.00842761
+    70       278     113.22261378       0.00612126
+    80       318     111.97918998       0.00674140
+    90       352     110.85741565       0.00471266
+   100       390     110.07596824       0.00504442
+   110       424     109.22542801       0.00857797
+   120       474      96.41782444       0.02745573
+   130       521      64.42518274       0.03921470
+   140       574      29.96112250       0.04534468
+   150       617      14.85584990       0.01242338
+   160       654      13.54323681       0.00849761
+   170       683      13.42992225       0.00257693
+   180       708      13.38722877       0.00084105
+   190       729      13.38200130       0.00078035
+   200       749      13.38058904       0.00038853
+   210       769      13.38020522       0.00021774
+   220       789      13.38001729       0.00008396
+   230       809      13.37997848       0.00007880
+   240       829      13.37996288       0.00003219
+   250       849      13.37995884       0.00002386
+   260       869      13.37995720       0.00001138
+   270       889      13.37995698       0.00000356
+   280       909      13.37995692       0.00000097
+

Check the output

It's important to check the output of the optimization method. In particular, it's worthwhile to check the exit flag. A zero (0) indicates successful termination with the gradient smaller than the specified StopTol, and a three (3) indicates a successful termination where the change in function value is less than RelFuncTol. The meaning of any other flags can be checked via doc poblano_params.

exitflag = output.ExitFlag
+
+exitflag =
+
+     0
+
+

Evaluate the output

We can "score" the similarity of the model computed by CP and compare that with the truth. The score function on ktensor's gives a score in [0,1] with 1 indicating a perfect match. Because we have noise, we do not expect the fit to be perfect. See doc score for more details.

scr = score(M,M_true)
+
+scr =
+
+    0.9989
+
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/T4_cpapr_doc.html b/external/tensor_toolbox_2.5/doc/html/T4_cpapr_doc.html new file mode 100755 index 0000000..a75bac4 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/T4_cpapr_doc.html @@ -0,0 +1,157 @@ + + + + + Alternating Poisson Regression for fitting CP to sparse count data

Alternating Poisson Regression for fitting CP to sparse count data

Contents

Set up a sample problem

We follow the general procedure outlined by E. C. Chi and T. G. Kolda, On Tensors, Sparsity, and Nonnegative Factorizations, arXiv:1112.2414 [math.NA], December 2011 (http://arxiv.org/abs/1112.2414).

% Pick the size and rank
+sz = [100 80 60];
+R = 5;
+
+% Generate factor matrices with a few large entries in each column; this
+% will be the basis of our soln.
+A = cell(3,1);
+for n = 1:length(sz)
+    A{n} = rand(sz(n), R);
+    for r = 1:R
+        p = randperm(sz(n));
+        nbig = round( (1/R)*sz(n) );
+        A{n}(p(1:nbig),r) = 100 * A{n}(p(1:nbig),r);
+    end
+end
+lambda = rand(R,1);
+S = ktensor(lambda, A);
+S = normalize(S,'sort',1);
+
+% Create sparse test problem based on provided solution.
+nz = prod(sz) * .05;
+info = create_problem('Soln', S, 'Sparse_Generation', nz);
+
+% Extract data and solution
+X = info.Data;
+M_true = info.Soln;
+

Call CP-APR

% Compute a solution
+M = cp_apr(X, R, 'printitn', 10);
+
+% Score the solution
+factor_match_score = score(M, M_true, 'greedy', true)
+
+CP_APR:
+ Iter   10: Inner Its = 30 KKT violation = 7.602374e-002, nViolations =  0
+ Iter   20: Inner Its = 30 KKT violation = 5.132380e-002, nViolations =  0
+ Iter   30: Inner Its = 30 KKT violation = 5.515916e-004, nViolations =  0
+===========================================
+ Final log-likelihood = -8.281889e+003 
+ Final least squares fit = 5.784579e-001 
+ Final KKT violation = 9.9202395e-005
+ Total inner iterations = 1034
+
+factor_match_score =
+
+    0.9610
+
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc.html b/external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc.html new file mode 100755 index 0000000..b81c4b0 --- /dev/null +++ b/external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc.html @@ -0,0 +1,122 @@ + + + + + Shifted Symmetric Higher-Order Power Method (SSHOPM)

Shifted Symmetric Higher-Order Power Method (SSHOPM)

Contents

Data tensor

From Example 1 in E. Kofidis and P. A. Regalia, On the best rank-1 approximation of higher-order supersymmetric tensors, SIAM J. Matrix Anal. Appl., 23 (2002), pp. 863–884, DOI: 10.1137/S0895479801387413.

A = tenzeros([3 3 3 3]);
+A(perms([1 1 1 1])) = 0.2883;
+A(perms([1 1 1 2])) = -0.0031;
+A(perms([1 1 1 3])) = 0.1973;
+A(perms([1 1 2 2])) = -0.2485;
+A(perms([1 1 2 3])) = -0.2939;
+A(perms([1 1 3 3])) = 0.3847;
+A(perms([1 2 2 2])) = 0.2972;
+A(perms([1 2 2 3])) = 0.1862;
+A(perms([1 2 3 3])) = 0.0919;
+A(perms([1 3 3 3])) = -0.3619;
+A(perms([2 2 2 2])) = 0.1241;
+A(perms([2 2 2 3])) = -0.3420;
+A(perms([2 2 3 3])) = 0.2127;
+A(perms([2 3 3 3])) = 0.2727;
+A(perms([3 3 3 3])) = -0.3054;
+

Call SSHOPM with no shift

The method with no shift will fail to converge.

[lambda, x, flag, it, ~, trace] = sshopm(A, 'MaxIts', 100);
+plot(0:it, trace(1:it+1),'b.-');
+

Call SSHOPM with shift

[lambda, x, flag, it, ~, trace] = sshopm(A, 'MaxIts', 100, 'Shift', 1);
+plot(0:it, trace(1:it+1),'b.-');
+
\ No newline at end of file diff --git a/external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc.png b/external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc.png new file mode 100755 index 0000000000000000000000000000000000000000..d281b07a13c3a6cee09ef7c91dffd54b5cefdeb2 GIT binary patch literal 1669 zcmV;027394P)Vh#s5Cl(qJ^cuwt*xziJbvobDYsqI zG+CB0-uAyMD=VX;qi%~~7yzIsirbh>CeNHXAZ)f)FxS}jXUOT5Si&p)r*>^agitk$@n(sspBAODW^bI9lO zgpke6%~rOi^>~l}l+sixH8?mpH#dhdwk%7Mq-Ipl7&vpQAb@S};<|Gz%St9wmo8oM z^m^+TMX|rXzqhyd&Ye5)c)S_n8H1-!!Lk4VHa8&@fJ}8$#mccXuW1tie`v0~vCdu;Hy?cPYv~uVFs(JOmdHE6^Jb>ZhrdINg zZ&!Q9KgJ*&Zjt!iTOz{eFZF@-dm2f$dpbb3q98^z?AOJjec13m(J6(A(RjvUg3Z$G_E8FwGX%S&vrh zfBznC+-Px~_2BCN{rk6J80mES04rNug!AWHI`TKfTR){VlgSW5Ow-I}vzD_=-z&Ba z};E{}Dop zq9BBPKA)m=s(9Gj`d<))>FMccGT?=5jfnmz)1cl4M!dg$oxH#V2-h2M|Ru z91iom-2CU-wQHeJXkucbR1!LU{kyOHr@J}U--zwUP`eFo{`2nLyHcsNxVRV!b@1Zf zq0at2H~+D1+p?@;u~;Y+2q8^tThk$gWHK3^*IU0Rir24S4~0UvZr#%LKJ0mPtV6&U z4-E}*y*!6A=L>>xc=qa>LF4gn`%(IC<9Pn#plKRo%=y(t6`sRsZI0mlz@WdyL6s77=@Xwz=&z?Q&wv@|d0Py*I zZsYgw-zO(0-4;TKuIp7>6t!WVrPWqS2q~A#!R>Es^ZC4|OyKE92%R`_LRHnCo*r42 zCnqN>$DwT7URzr$l}b}nQp{u7JEB9TZm8g*{G;3An!Zf$K<8FRT@u~@A9i4a;}U)Ocr9rpI^ z+e9Lf%jGH-O6kVNhI7QQV*L8`>(bKFpFe*p7Eu%ffk0JhtE;OYK72^0(-jK`usP!z|0P zZM!OrF=m>kJB$#*7!yU&ot~Sf$ry8oQA(ZjJ5?%ns=vEAp8t+EM_vDaW9Ql@P#cJ) P00000NkvXXu0mjfSdUGw literal 0 HcmV?d00001 diff --git a/external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc_01.png b/external/tensor_toolbox_2.5/doc/html/V_SSHOPM_doc_01.png new file mode 100755 index 0000000000000000000000000000000000000000..3971ed4416ca5c57768a502443ef4450454b4fec GIT binary patch literal 3506 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 literal 0 HcmV?d00001 diff --git a/external/tensor_toolbox_2.5/doc/images/banner-background.jpg b/external/tensor_toolbox_2.5/doc/images/banner-background.jpg new file mode 100755 index 0000000000000000000000000000000000000000..549ee8b94b1939eaeea804293fc0a7fe7eb52e1d GIT binary patch literal 7479 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 literal 0 HcmV?d00001 diff --git a/external/tensor_toolbox_2.5/doc/images/logo.gif b/external/tensor_toolbox_2.5/doc/images/logo.gif new file mode 100755 index 0000000000000000000000000000000000000000..913d194de220324ee0cbd7256f920333b996c060 GIT binary patch literal 5695 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 literal 0 HcmV?d00001 diff --git a/external/tensor_toolbox_2.5/export_data.m b/external/tensor_toolbox_2.5/export_data.m new file mode 100755 index 0000000..ef71f2e --- /dev/null +++ b/external/tensor_toolbox_2.5/export_data.m @@ -0,0 +1,85 @@ +function export_data(A, fname) +%EXPORT_DATA Export tensor-related data to a file. +% +% EXPORT(A,FNAME) exports object A to the file named FNAME in plain ASCII +% text. Export currently supports exporting the following data types: +% +% - tensor +% - matrix +% +% In the case of a tensor, the first three lines give details about the +% tensor. The format for a 4 x 3 x 2 tensor is as follows... +% +% tensor +% 3 +% 4 3 2 +% +% +% +% +% +% +% +% +% ... +% +% +% +% +% A matrix is formatted the same as a 2-way tensor except that the first +% line says "matrix" rather than "tensor". +% +% See also TENSOR, IMPORT_DATA +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +%% Open file +fid = fopen(fname,'w'); +if (fid == -1) + error('Cannot open file %s',fname); +end + +%% Export the object + +if isa(A,'tensor') + + fprintf(fid, 'tensor\n'); + export_size(fid, size(A)); + export_array(fid, A.data); + +elseif isnumeric(A) && ndims(A) == 2 + + fprintf(fid, 'matrix\n'); + export_size(fid, size(A)); + export_array(fid, A); + +else + + error('Invalid data type for export'); + +end + + +%% Close file +fclose(fid); + +function export_size(fid, sz) +% Export the size of something to a file +fprintf(fid, '%d \n', length(sz)); % # of dimensions on one line +fprintf(fid, '%d ', sz); % # size of each dimensions on the next line +fprintf(fid, '\n'); + +function export_array(fid, data) +% Export dense data that supports numel and linear indexing +for i = 1:numel(data) + fprintf(fid, '%.16e\n', data(i)); +end diff --git a/external/tensor_toolbox_2.5/helpindex.xml b/external/tensor_toolbox_2.5/helpindex.xml new file mode 100755 index 0000000..b993639 --- /dev/null +++ b/external/tensor_toolbox_2.5/helpindex.xml @@ -0,0 +1,6 @@ + + + + +Tensor Toolbox + \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/helptoc.xml b/external/tensor_toolbox_2.5/helptoc.xml new file mode 100755 index 0000000..e2b793f --- /dev/null +++ b/external/tensor_toolbox_2.5/helptoc.xml @@ -0,0 +1,43 @@ + + + + + +Tensor + +Tensors +Sparse Tensors +Converting a tensor to a matrix and vice versa +Converting sparse tensors to matrices and vice versa +Tucker Tensors +Kruskal tensors +Multiplying tensors +Generating the leading mode-n vectors +Collapsing and scaling tensors +Creating test problems and initial guesses +ALS optimization for CP and Tucker tensor decompositions +All-at-once optimization for CP tensor decomposition +Weighted optimization for CP tensor decomposition with incomplete data +Alternating Poisson Regression for fitting CP to sparse count data +Shifted Symmetric Higher-Order Power Method (SSHOPM) + +Tensor Toolbox Site + + + diff --git a/external/tensor_toolbox_2.5/import_data.m b/external/tensor_toolbox_2.5/import_data.m new file mode 100755 index 0000000..e79dfa1 --- /dev/null +++ b/external/tensor_toolbox_2.5/import_data.m @@ -0,0 +1,69 @@ +function A = import_data(fname) +%IMPORT_DATA Import tensor-related data to a file. +% +% A = IMPORT_DATA(FNAME) imports an object A from the file named FNAME. +% The supported data types and formatting of the file are explained in +% EXPORT_DATA. +% +% See also TENSOR, EXPORT_DATA +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Open file +fid = fopen(fname,'r'); +if (fid == -1) + error('Cannot open file %s',fname); +end + +%% Get the type of object +line = fgets(fid); +type = sscanf(line, '%s'); + +%% Import the object + +if strcmpi(type,'tensor') + + sz = import_size(fid); + data = import_array(fid, prod(sz)); + A = tensor(data, sz); + +elseif strcmpi(type,'matrix') + + sz = import_size(fid); + data = import_array(fid, prod(sz)); + A = reshape(data, sz); + +else + + error('Invalid data type for export'); + +end + + +%% Close file +fclose(fid); + +function sz = import_size(fid) +% Import the size of something from a file +line = fgets(fid); +n = sscanf(line, '%d'); +line = fgets(fid); +sz = sscanf(line, '%d'); +sz = sz'; +if (size(sz,2) ~= n) + error('Imported dimensions are not of expected size'); +end + +function data = import_array(fid, n) +% Export dense data that supports numel and linear indexing +data = fscanf(fid, '%e', n); diff --git a/external/tensor_toolbox_2.5/info.xml b/external/tensor_toolbox_2.5/info.xml new file mode 100755 index 0000000..b34cbed --- /dev/null +++ b/external/tensor_toolbox_2.5/info.xml @@ -0,0 +1,25 @@ + + + +R2006a +Tensor +toolbox +$toolbox/matlab/icons/unknownicon.gif +. + + + + + doc tensor_toolbox/ + $toolbox/matlab/icons/webicon.gif + + + + web http://www.sandia.gov/~tgkolda/TensorToolbox + $toolbox/matlab/icons/webicon.gif + + + + diff --git a/external/tensor_toolbox_2.5/khatrirao.m b/external/tensor_toolbox_2.5/khatrirao.m new file mode 100755 index 0000000..7a912da --- /dev/null +++ b/external/tensor_toolbox_2.5/khatrirao.m @@ -0,0 +1,95 @@ +function P = khatrirao(varargin) +%KHATRIRAO Khatri-Rao product of matrices. +% +% KHATRIRAO(A,B) computes the Khatri-Rao product of matrices A and +% B that have the same number of columns. The result is the +% column-wise Kronecker product +% [KRON(A(:,1),B(:,1)) ... KRON(A(:,n),B(:,n))] +% +% KHATRIRAO(A1,A2,...) computes the Khatri-Rao product of +% multiple matrices that have the same number of columns. +% +% KHATRIRAO(C) computes the Khatri-Rao product of +% the matrices in cell array C. +% +% KHATRIRAO(...,'r') computes the Khatri-Rao product in reverse +% order. +% +% Examples +% A = rand(5,2); B = rand(3,2); C = rand(2,2); +% khatrirao(A,B) %<-- Khatri-Rao of A and B +% khatrirao(B,A,'r') %<-- same thing as above +% khatrirao({C,B,A}) %<-- passing a cell array +% khatrirao({A,B,C},'r') %<-- same as above +% +% See also TENSOR, KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Error checking on input and set matrix order +% Note that this next if/else check forces A to be a cell array. +if ischar(varargin{end}) && varargin{end} == 'r' + if nargin == 2 && iscell(varargin{1}) + % Input is a single cell array + A = varargin{1}; + else + % Input is a sequence of matrices + A = {varargin{1:end-1}}; + end + matorder = length(A):-1:1; +else + if nargin == 1 && iscell(varargin{1}) + % Input is a single cell array + A = varargin{1}; + else + % Input is a sequence of matrices + A = varargin; + end + matorder = 1:length(A); +end + +%% Error check on matrices and compute number of rows in result + +% N = number of columns (must be the same for every input) +N = size(A{1},2); + +% After loop, M = number of rows in the result +M = 1; + +for i = matorder + if ndims(A) ~= 2 + error('Each argument must be a matrix'); + end + if (N ~= size(A{i},2)) + error('All matrices must have the same number of columns.') + end + M = M * size(A{i},1); +end + +%% Computation + +% Preallocate +P = zeros(M,N); + +% Loop through all the columns +for n = 1:N + % Loop through all the matrices + ab = A{matorder(1)}(:,n); + for i = matorder(2:end) + % Compute outer product of nth columns + ab = A{i}(:,n) * ab(:).'; + end + % Fill nth column of P with reshaped result + P(:,n) = ab(:); +end + diff --git a/external/tensor_toolbox_2.5/met/Contents.m b/external/tensor_toolbox_2.5/met/Contents.m new file mode 100755 index 0000000..49317e1 --- /dev/null +++ b/external/tensor_toolbox_2.5/met/Contents.m @@ -0,0 +1,8 @@ +% MET: Memory Efficient Tucker +% +% Files +% ttm_me - Memory-efficient sptensor times matrix. +% ttm_me_mem - Estimates intermediate memory comsumption for ttm_me. +% ttm_me_partition - Finds best order for ttm_me. +% tucker_me - Memory-efficient Tucker higher-order orthogonal iteration. +% tucker_me_test - Very simple tests of tucker_me. diff --git a/external/tensor_toolbox_2.5/met/ttm_me.m b/external/tensor_toolbox_2.5/met/ttm_me.m new file mode 100755 index 0000000..afdb180 --- /dev/null +++ b/external/tensor_toolbox_2.5/met/ttm_me.m @@ -0,0 +1,157 @@ +function Y = ttm_me(X, U, edims, sdims, tflag) +%TTM_ME Memory-efficient sptensor times matrix. +% +% Y = TTM_ME(X, U, EDIMS, SDIMS, TFLAG) handles some dimensions +% elementwise and others in the standard way. Here, X is a sparse tensor +% (sptensor), U is a cell array of matrices of length ndims(X), +% EDIMS specifies the dimensions that are to be handled elementwise, and +% SDIMS specifies those dimensions that are to be handled in the standard +% way, and TFLAG indicates to multiply with matrix transpose. Ultimately, +% the result should be equivalent to called TTM(X, U, [EDIMS SDIMS]) but +% will use less memory in the computation. +% +% See also TENSOR_TOOLBOX, SPTENSOR/TTM, TUCKER_ME, TTM_ME_PARTITION. +% +% Code by Tamara Kolda and Jimeng Sun, 2008. Adapted with permission from +% the MATLAB Tensor Toolbox function @sptensor/ttm. +% +% Based on the paper: +% T. G. Kolda and J. Sun. Scalable Tensor Decompositions for Multi-aspect +% Data Mining. In: ICDM 2008: Proceedings of the 8th IEEE International +% Conference on Data Mining, December 2008. + +% $Id: ttm_me.m,v 1.2 2009/07/08 00:03:52 tgkolda Exp $ + +%% Setup and error checking + +% Check number of input arguments +if (nargin < 4) + error('TTM_ME requires four arguments'); +end +if (nargin==4) + tflag = ''; +else + tflag = 't'; +end +% Check that X is a sparse tensor +if ~isa(X, 'sptensor') + error('Input tensor X must be sparse'); +end + +% Set number of dimensions of X +N = ndims(X); + +% Check that U is a cell array +if ~iscell(U) + error('U must be a cell array'); +end + +% Check that the cell array U +if numel(U) ~= N + error('Incorrect number of elements in U'); +end + +% Check that every member of edims is in 1:N +tf = ismember(edims, 1:N); +if min(tf) == 0 + error('Invalid dimensions specified'); +end + +% Check that every member of sdims is in 1:N +tf = ismember(sdims, 1:N); +if min(tf) == 0 + error('Invalid dimensions specified'); +end + +% Check that edims and sdims are distinct +idx = intersect(edims, sdims); +if ~isempty(idx) + error('Invalid dimensions specified'); +end + +%% Check for special case of empty edims +% This means that none of the modes is to be handled elementwise +if isempty(edims) + Y = ttm(X, U, sdims, tflag); + return; +end + +%% Determine some sizes and set up some variables and mappings + +% Determine size of Y (final result) +sizY = size(X); +for n = union(edims, sdims) + if strcmp(tflag,'t') + sizY(n) = size(U{n}, 2); + else + sizY(n) = size(U{n}, 1); + end +end + +% Allocate space for Y (final result) +Y = tenzeros(sizY); + +% Set up cell array of vectors for elementwise computations +v = cell(length(edims), 1); + +% Set up mapping from sdims on X to appropriate dimensions on Z +% (zdims) as well as array of matrices (M). +zmap = -1 * ones(1,N); +j = 0; +for i = 1:N + if ~ismember(i, edims) + j = j+1; + zmap(i) = j; + M{j} = U{i}; + end +end +zdims = zmap(sdims); + +%% Main Loop +for i = 1:prod(sizY(edims)) + % Get the subscripts of the rows to be extracted + rsubs = tt_ind2sub(sizY(edims), i); + + % Extract the appropriate rows of the U matrices + for j = 1:length(edims) + if strcmp(tflag,'t') + v{j} = U{edims(j)}(:, rsubs(j)); + else + v{j} = (U{edims(j)}(rsubs(j), :))'; + end + end + + % Create argument to pass into tensor/subsasgn + rsubsarg = makesubsarg(N, edims, rsubs); + + % Assign to appropriate part of Y + if isempty(zdims) + % Case 1: Assigning a single element of Y + t1 = ttv(X, v, edims); + Y = subsasgn(Y, rsubsarg, t1); + else + % Case 2: Assigning an entire subtensor + Z = ttv(X, v, edims); + if nnz(Z)==0 + tmp = 0; + else + tmp = full(ttm(Z, M, zdims,tflag)); + end + Y = subsasgn(Y, rsubsarg, tmp); + end + +end + +%% +function s = makesubsarg(n, edims, rsubs) +s.type = '()'; +s.subs = cell(1, n); +j = 1; +for i = 1:n + if ismember(i, edims) + s.subs{i} = [rsubs(j)]; + j = j + 1; + else + s.subs{i} = ':'; + end +end \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/met/ttm_me_mem.m b/external/tensor_toolbox_2.5/met/ttm_me_mem.m new file mode 100755 index 0000000..91a926c --- /dev/null +++ b/external/tensor_toolbox_2.5/met/ttm_me_mem.m @@ -0,0 +1,89 @@ +function [max_mem] = ttm_me_mem(X, U, edims, sdims, tflag) +%TTM_ME_MEM Estimates intermediate memory comsumption for ttm_me. +% +% MAX_MEM = TTM_ME_MEM(X, U, EDIMS, SDIMS, TFLAG) estimates the memory +% comsumption used in the TTM_ME function. Here, X is a sparse tensor +% (sptensor), U is a cell array of matrices of length ndims(X), +% EDIMS specifies the dimensions that are to be handled elementwise, sdims +% specifies those dimensions that are to be handled in the standard way, +% and TFLAG indicates to multiply the matrix transpose. +% +% See also TENSOR_TOOLBOX, TUCKER_ME, TTM_ME. +% +% Code by Tamara Kolda and Jimeng Sun, 2008. +% +% Based on the paper: +% T. G. Kolda and J. Sun. Scalable Tensor Decompositions for Multi-aspect +% Data Mining. In: ICDM 2008: Proceedings of the 8th IEEE International +% Conference on Data Mining, December 2008. + +% $Id: ttm_me_mem.m,v 1.2 2009/07/08 00:03:52 tgkolda Exp $ + +%% Setup and error checking + +% Check number of input arguments +if (nargin < 4) + error('TTM_ME requires four arguments'); +end +if (nargin == 4) + tflag = ''; +else + tflag = 't'; +end +% Check that X is a sparse tensor +if ~isa(X, 'sptensor') + error('Input tensor X must be sparse'); +end + +% Set number of dimensions of X +N = ndims(X); + +% Check that U is a cell array +if ~iscell(U) + error('U must be a cell array'); +end + +% Check that the cell array U +if numel(U) ~= N + error('Incorrect number of elements in U'); +end + +% Check that every member of edims is in 1:N +tf = ismember(edims, 1:N); +if min(tf) == 0 + error('Invalid dimensions specified'); +end + +% Check that every member of sdims is in 1:N +tf = ismember(sdims, 1:N); +if min(tf) == 0 + error('Invalid dimensions specified'); +end + +% Check that edims and sdims are distinct +idx = intersect(edims, sdims); +if ~isempty(idx) + error('Invalid dimensions specified'); +end + +%% Calculate the max memory from two sources +% 1. intermediate tensor + sizY = size(X); + for n = edims + sizY(n) = 1; + end + % special case for the MET(0) or original Tucker-ALS + if isempty(edims) + if strcmp(tflag, 't') + sizY(sdims(1)) = size(U{sdims(1)}, 2); + else + sizY(sdims(1)) = size(U{sdims(1)}, 1); + end + end + mem = prod(sizY); +% 2. ttv + if ~isempty(edims) + mem = mem + nnz(X); + end + max_mem = mem; +end \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/met/ttm_me_partition.m b/external/tensor_toolbox_2.5/met/ttm_me_partition.m new file mode 100755 index 0000000..1784737 --- /dev/null +++ b/external/tensor_toolbox_2.5/met/ttm_me_partition.m @@ -0,0 +1,38 @@ +function [edims, sdims] = ttm_me_partition(U, esz, n) +%TTM_ME_PARTITION Finds best order for ttm_me. +% +% [EDIMS, SDIMS] = TTM_ME_PARTITION(U, ESZ, N) finds the best order for +% memory efficient ttm. ESZ specifies the number of dimensions that +% are to be handled elementwise. U is the cell array of matrices. +% The result returned in EDIMS and SDIMS are the modes that need to +% be handled in element-wise and in slice-wise respectively. The +% orders are in the descending order of the reduction ratio. +% +% See also TUCKER_ME, TTM_ME. +% +% Based on the paper: +% T. G. Kolda and J. Sun. Scalable Tensor Decompositions for Multi-aspect +% Data Mining. In: ICDM 2008: Proceedings of the 8th IEEE International +% Conference on Data Mining, December 2008. + +% $Id: ttm_me_partition.m,v 1.2 2009/07/08 00:03:52 tgkolda Exp $ + +if nargin<3 + %default: n is not in 1:length(U) + n = -1; +end + +% compute reduction ratios +dims = setdiff(1:length(U), n); +r = []; +for i=dims + [nr, nc] = size(U{i}); + r(end+1) = nr/nc; +end + +%sort the reduction ratio and +%put the ones w/ highest reduction ratio in edims +[junk, ind] = sort(r,'descend'); +edims = sort(dims(ind(1:min(length(ind),esz)))); +sdims = sort(dims(ind(esz+1:end))); +end \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/met/tucker_me.m b/external/tensor_toolbox_2.5/met/tucker_me.m new file mode 100755 index 0000000..b305d5b --- /dev/null +++ b/external/tensor_toolbox_2.5/met/tucker_me.m @@ -0,0 +1,154 @@ +function [T, max_mem, Uinit] = tucker_me(X, R, esz, opts) +%TUCKER_ME Memory-efficient Tucker higher-order orthogonal iteration. +% +% T = TUCKER_ME(X,R,ESZ) computes the best rank(R1,R2,..,Rn) +% approximation of tensor X, according to the specified dimensions +% in vector R. ESZ specifies the number of dimensions that are to be +% handled elementwise. The input X is sptensor. The result +% returned in T is a ttensor. +% +% T = TUCKER_ME(X,R,ESZ,OPTS) specify options: +% OPTS.tol: Tolerance on difference in fit {1.0e-4} +% OPTS.maxiters: Maximum number of iterations {50} +% OPTS.dimorder: Order to loop through dimensions {1:ndims(A)} +% OPTS.init: Initial guess [{'random'}|'eigs'|cell array] +% +% [T,MEM,U0] = TUCKER_ME(...) also returns the memory estimate and +% the initial guess U0. +% +% See also TENSOR_TOOLBOX, TUCKER_ALS, TTM_ME, TTM_ME_PARTITION, +% TTM_ME_MEM. +% +% Code by Tamara Kolda and Jimeng Sun, 2008. Adapted with permission from +% the MATLAB Tensor Toolbox function algorithms/tucker_als. +% +% Based on the paper: +% T. G. Kolda and J. Sun. Scalable Tensor Decompositions for Multi-aspect +% Data Mining. In: ICDM 2008: Proceedings of the 8th IEEE International +% Conference on Data Mining, December 2008. + +% $Id: tucker_me.m,v 1.3 2010/03/19 22:55:46 tgkolda Exp $ + + +%% Fill in optional variable +if ~exist('opts','var') + opts = struct; +end + +%% Extract number of dimensions and norm of X. +N = ndims(X); +normX = norm(X); + +%% Set algorithm parameters from input or by using defaults +fitchangetol = setparam(opts,'tol',1e-4); +maxiters = setparam(opts,'maxiters',50); +dimorder = setparam(opts,'dimorder',1:N); +init = setparam(opts,'init','random'); + +if numel(R) == 1 + R = R * ones(N,1); +end + +%% Error checking +% Error checking on maxiters +if maxiters < 0 + error('OPTS.maxiters must be positive'); +end + +% Error checking on dimorder +if ~isequal(1:N,sort(dimorder)) + error('OPTS.dimorder must include all elements from 1 to ndims(X)'); +end + +%% Set up and error checking on initial guess for U. +if iscell(init) + Uinit = init; + if numel(Uinit) ~= N + error('OPTS.init does not have %d cells',N); + end + for n = dimorder(2:end); + if ~isequal(size(Uinit{n}),[size(X,n) R(n)]) + error('OPTS.init{%d} is the wrong size',n); + end + end +else + % Observe that we don't need to calculate an initial guess for the + % first index in dimorder because that will be solved for in the first + % inner iteration. + if strcmp(init,'random') + Uinit = cell(N,1); + for n = dimorder(2:end) + Uinit{n} = rand(size(X,n),R(n)); + end + elseif strcmp(init,'nvecs') || strcmp(init,'eigs') + % Compute an orthonormal basis for the dominant + % Rn-dimensional left singular subspace of + % X_(n) (1 <= n <= N). + Uinit = cell(N,1); + for n = dimorder(2:end) + fprintf(' Computing %d leading e-vectors for factor %d.\n', ... + R(n),n); + Uinit{n} = nvecs(X,n,R(n)); + end + else + error('The selected initialization method is not supported'); + end +end + +%% Set up for iterations - initializing U, fit, and max_mem +U = Uinit; +fit = 0; +max_mem = 0; + +%% Main Loop: Iterate until convergence +fprintf('\nAlternating Least-Squares:\n'); +for iter = 1:maxiters + fitold = fit; + + % Iterate over all N modes of the tensor + for n = dimorder(1:end) + % Estimate the best partition of edims and sdims based on n + [ed, sd] = ttm_me_partition(U, esz, n); + Utilde = ttm_me(X, U, ed, sd, 't'); + % Check memory + mem = ttm_me_mem(X, U, ed, sd, 't'); + max_mem = max(mem, max_mem); + % Maximize norm(Utilde x_n W') wrt W and + % keeping orthonormality of W + U{n} = nvecs(Utilde,n,R(n)); + end + + % Assemble the current approximation + core = ttm(Utilde, U, n, 't'); + + % Compute fit + normresidual = sqrt( normX^2 - norm(core)^2); + fit = 1 - (normresidual / normX); % fraction explained by model + fitchange = abs(fitold - fit); + + fprintf(' Iter %2d: fit = %e fitdelta = %7.1e\n', iter, fit, fitchange); + + % Check for convergence + if (iter > 1) && (fitchange < fitchangetol) + break; + end + +end + +%% Compute the final result %commented by Jimeng Sun, seems redundant +max_mem = max(mem, max_mem); + +%% Assemble the resulting tensor +T = ttensor(core, U); +end + +%% +function x = setparam(opts,name,default) +if isfield(opts,name); + x = opts.(name); +else + x = default; +end +end +%% + \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/met/tucker_me_test.m b/external/tensor_toolbox_2.5/met/tucker_me_test.m new file mode 100755 index 0000000..8875c84 --- /dev/null +++ b/external/tensor_toolbox_2.5/met/tucker_me_test.m @@ -0,0 +1,105 @@ +function tucker_me_test +%TUCKER_ME_TEST Very simple tests of tucker_me. +% Code by Tamara Kolda and Jimeng Sun, 2008. +% +% Based on the paper: +% T. G. Kolda and J. Sun. Scalable Tensor Decompositions for Multi-aspect +% Data Mining. In: ICDM 2008: Proceedings of the 8th IEEE International +% Conference on Data Mining, December 2008. + +% $Id: tucker_me_test.m,v 1.2 2009/07/08 00:03:52 tgkolda Exp $ + + +%% Set up +csz = [3 6 9 12]; +tsz = [50 50 50 50]; +X = tucker_me_test_gendata(csz, tsz, .001); + +%% +fprintf('-----------------------------------------------------------\n'); +fprintf('%-20s | %-7s | %-10s |%-10s \n','Method','Time(s)','Error', 'Memory ratio'); +fprintf('-----------------------------------------------------------\n'); +%% +tic +[T,Uinit] = tucker_als(X,csz); +t = toc; +fprintf('%-20s | %7.2f | %10.3e \n', 'tucker_als (standard)', t, 1-norm(T)/norm(X)); + +% Make sure that they all use the same initial guess +opts.init = Uinit; + +tic +[T, mem_orig] = tucker_me(X,csz, 0, opts); +t = toc; +fprintf('%-20s | %7.2f | %10.3e |%f \n', 'tucker_me (standard)', t, 1-norm(T)/norm(X), 1); + + +%% +tic +[T,mem] = tucker_me(X,csz,1,opts); +t = toc; +fprintf('%-20s | %7.2f | %10.3e|%f \n', 'tucker_me (slicewise)', t, 1-norm(T)/norm(X), mem/mem_orig); + +%% +tic +[T,mem] = tucker_me(X,csz,2,opts); +t = toc; +fprintf('%-20s | %7.2f | %10.3e |%f \n', 'tucker_me (fiberwise)', t, 1-norm(T)/norm(X), mem/mem_orig); + +%% Really slow! +tic +[T,mem] = tucker_me(X,csz,3,opts); +t = toc; +fprintf('%-20s | %7.2f | %10.3e |%f \n', 'tucker_me (elementwise)', t, 1-norm(T)/norm(X), mem/mem_orig); + +%---------------------------------------------------------------------- +function [X,G,U] = tucker_me_test_gendata(csz,tsz,pnz) +%TUCKER_ME_TEST_GENDATA Generate sparse array for tucker_me tests. +% +% X = GENDATA(CSZ,TSZ,PNZ) generates a tensor as follows. 1) Randomly +% generates a core tensor, G, of size CSZ. 2) Expand it into a tensor of +% size TSZ by multiplying it by appropriately sized random matrices in +% each mode. 3) Save only the largest nonzeros, as specified by PNZ, the +% percentage of nonzeros to be saved. +% +% [X,G,U] = GENDATE(...) also returns the core tensor and matrices that +% were use to generate X. +% +% Example +% X = gendata([2 2 2], [10 10 10], .10) - generates a tensor of size 10 x +% 10 x 10 that came from a core of size 2 x 2 x 2 but where the smallest +% entries were deleted. +% +% See also TUCKER_ME_TEST. +% +% Code by Tamara Kolda and Jimeng Sun, 2008. +% +% Based on the paper: +% T. G. Kolda and J. Sun. Scalable Tensor Decompositions for Multi-aspect +% Data Mining. In: ICDM 2008: Proceedings of the 8th IEEE International +% Conference on Data Mining, December 2008. + + +% Number of tensor dimensions +N = length(csz); + +% Generate random core tensor +G = tenrand(csz); + +% Generate random U-matrices +for n = 1:N + U{n} = rand( [tsz(n), csz(n)] ); +end + +% Create full tensor +Xfull = ttm(G,U); + +% Sparsify +[v,idx] = sort(Xfull(:),'descend'); +stop = round( pnz * length(idx) ); +v(stop:end) = 0; +X = sptensor( reshape(v,size(Xfull)) ); + + + + diff --git a/external/tensor_toolbox_2.5/parafac_als.m b/external/tensor_toolbox_2.5/parafac_als.m new file mode 100755 index 0000000..017d978 --- /dev/null +++ b/external/tensor_toolbox_2.5/parafac_als.m @@ -0,0 +1,32 @@ +function [P,Uinit] = parafac_als(X,R,opts) +%PARAFAC_ALS Deprecated. Use CP_ALS instead. +% +% See also CP_ALS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if (nargout == 2) & (nargin == 3) + [P,Uinit] = cp_als(X,R,opts); +elseif (nargout == 2) & (nargin == 2) + [P,Uinit] = cp_als(X,R); +elseif (nargout == 2) & (nargin == 1) + [P,Uinit] = cp_als(X); +elseif (nargout == 1) & (nargin == 3) + P = cp_als(X,R,opts); +elseif (nargout == 1) & (nargin == 2) + P = cp_als(X,R); +elseif (nargout == 1) & (nargin == 1) + P = cp_als(X); +end + + diff --git a/external/tensor_toolbox_2.5/sptendiag.m b/external/tensor_toolbox_2.5/sptendiag.m new file mode 100755 index 0000000..9d94ae4 --- /dev/null +++ b/external/tensor_toolbox_2.5/sptendiag.m @@ -0,0 +1,39 @@ +function X = sptendiag(v,sz) +%SPTENDIAG Creates a sparse tensor with v on the diagonal. +% +% SPTENDIAG(V) creates a sparse tensor with N dimensions, each of +% size N, where N is the number of elements of V. The elements of V +% are placed on the superdiagonal. +% +% SPTENDIAG(V,SZ) is the same as above but creates a tensor of size +% SZ. If SZ is not big enough, the tensor will be enlarged to +% accommodate the elements of V on the superdiagonal. +% +% Examples +% X = sptendiag([0.1 0.22 0.333]) %<-- creates a 3x3x3 sptensor +% +% See also SPTENSOR, TENDIAG. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Make sure v is a column vector +v = reshape(v,[numel(v) 1]); + +N = numel(v); +if ~exist('sz','var') + sz = repmat(N,1,N); +end + +X = sptensor(sz); +subs = repmat((1:N)', 1, length(sz)); +X(subs) = v; diff --git a/external/tensor_toolbox_2.5/sptenrand.m b/external/tensor_toolbox_2.5/sptenrand.m new file mode 100755 index 0000000..f24e641 --- /dev/null +++ b/external/tensor_toolbox_2.5/sptenrand.m @@ -0,0 +1,63 @@ +function Y = sptenrand(sz,nz) +%SPTENRAND Sparse uniformly distributed random tensor. +% +% R = SPTENRAND(sz,density) creates a random sparse tensor of the +% specified sz with approximately density*prod(sz) nonzero +% entries. +% +% R = SPTENRAND(sz,nz) creates a random sparse tensor of the +% specified sz with approximately nz nonzero entries. +% +% Example: R = sptenrand([5 4 2],12); +% +% See also SPTENSOR, TENRAND, RAND. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +% Error check on siz +if ndims(sz) ~= 2 || size(sz,1) ~= 1 + error('Size must be a row vector'); +end + +% Error check on nz +if ~exist('nz','var') || (nz < 0) + error('2nd argument must be positive'); +end + +% Is nz an number or a fraction? Ultimately want a number. +if (nz < 1) + nz = prod(sz) * nz; +end + +% Make sure nz is an integer +nz = ceil(nz); + +% Keep iterating until we find enough unique nonzeros or we +% give up +subs = []; +cnt = 0; +while (size(subs,1) < nz) && (cnt < 10) + subs = ceil( rand(nz, size(sz,2)) * diag(sz) ); + subs = unique(subs, 'rows'); + cnt = cnt + 1; +end + +% Extract nnz subscipts and create a corresponding list of +% values +nz = min(nz, size(subs,1)); +subs = subs(1:nz,:); +vals = rand(nz,1); + +Y = sptensor(subs,vals,sz); +return; diff --git a/external/tensor_toolbox_2.5/sshopm.m b/external/tensor_toolbox_2.5/sshopm.m new file mode 100755 index 0000000..ff5f4dd --- /dev/null +++ b/external/tensor_toolbox_2.5/sshopm.m @@ -0,0 +1,173 @@ +function [lambda,x,flag,its,x0,trace,tracex] = sshopm(A,varargin) +%SSHOPM Shifted power method for finding a real eigenpair of a real tensor. +% +% [LAMBDA,X]=SSHOPM(A) finds an eigenvalue (LAMBDA) and eigenvector (X) +% for the real tensor A such that Ax^{m-1} = lambda*x. +% +% [LAMBDA,X]=SSHOPM(A,parameter,value,...) can specify additional +% parameters as follows: +% +% 'Shift' : Shift in the eigenvalue calculation (Default: 0) +% 'MaxIts' : Maximum power method iterations (Default: 1000) +% 'Start' : Initial guess (Default: normal random vector) +% 'Tol' : Tolerance on norm of change in |lambda| (Default: 1e-16) +% 'Concave' : Treat the problem as concave rather than convex. +% (Default: true for negative shift; false otherwise.) +% 'Display' : Display every n iterations (Default: -1 for no display) +% +% [LAMBDA,X,FLAG]=SSHOPM(...) also returns a flag indicating convergence. +% +% FLAG = 0 => Succesfully terminated +% FLAG = -1 => Norm(X) = 0 +% FLAG = -2 => Maximum iterations exceeded +% +% [LAMBDA,X,FLAG,IT]=SSHOPM(...) also returns the number of iterations. +% +% [LAMBDA,X,FLAG,IT,X0]=SSHOPM(...) also returns the intial guess. +% +% [LAMBDA,X,FLAG,IT,X0,TRACE]=SSHOPM(...) also returns a trace of the +% lambda values at each iteration. +% +% REFERENCE: T. G. Kolda and J. R. Mayo, Shifted Power Method for +% Computing Tensor Eigenpairs, SIAM Journal on Matrix Analysis and +% Applications 32(4):1095-1124, October 2011 (doi:10.1137/100801482) +% +% See also SSHOPMC, TENSOR, SYMMETRIZE, ISSYMMETRIC. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Error checking on A +P = ndims(A); +N = size(A,1); + +if ~issymmetric(A) + error('Tensor must be symmetric.') +end + +%% Check inputs +p = inputParser; +p.addParamValue('Shift', 0); +p.addParamValue('MaxIts', 1000, @(x) x > 0); +p.addParamValue('Start', [], @(x) isequal(size(x),[N 1])); +p.addParamValue('Tol', 1.0e-16); +p.addParamValue('Display', -1, @isscalar); +p.addParamValue('Concave', -1); +p.parse(varargin{:}); + +%% Copy inputs +maxits = p.Results.MaxIts; +x0 = p.Results.Start; +shift = p.Results.Shift; +tol = p.Results.Tol; +display = p.Results.Display; +concave = p.Results.Concave; + +%% Check starting vector +if isempty(x0) + x0 = 2*rand(N,1)-1; +end + +if norm(x0) < eps + error('Zero starting vector'); +end + +%% Check concavity +if concave == -1 + concave = (shift < 0); +end + +%% Execute power method +if (display >= 0) + fprintf('TENSOR SHIFTED POWER METHOD: '); + fprintf('Shift = %g, ', shift); + fprintf('Concave = %d, ', concave); + fprintf('\n'); + fprintf('---- --------- ----- --------\n'); + fprintf('Iter Lambda Diff |newx-x|\n'); + fprintf('---- --------- ----- --------\n'); +end + +flag = -2; +x = x0 / norm(x0); +lambda = x'*ttsv(A,x,-1); + +trace = zeros(maxits,1); +trace(1) = lambda; +tracex = zeros(maxits,length(x)); +tracex(1,:) = x0; + +for its = 1:maxits + + newx = ttsv(A,x,-1) + shift * x; + + if (concave) + newx = -newx; + end + + nx = norm(newx); + if nx < eps, + flag = -1; + break; + end + newx = newx / nx; + + newlambda = newx'* ttsv(A,newx,-1); + + if norm(abs(newlambda-lambda)) < tol + flag = 0; + end + + if (display > 0) && ((flag == 0) || (mod(its,display) == 0)) + fprintf('%4d ', its); + % Lambda + fprintf('%9.6f ', newlambda); + d = newlambda-lambda; + if (d ~= 0) + if (d < 0), c = '-'; else c = '+'; end + fprintf('%ce%+03d ', c, round(log10(abs(d)))); + else + fprintf(' '); + end + % Change in X + fprintf('%8.6e ', norm(newx-x)); + % Line end + fprintf('\n'); + end + + x = newx; + lambda = newlambda; + trace(its+1) = lambda; + tracex(its+1,:) = x; + + if flag == 0 + break + end +end + +%% Check results +if (display >=0) + switch(flag) + case 0 + fprintf('Successful Convergence'); + case -1 + fprintf('Converged to Zero Vector'); + case -2 + fprintf('Exceeded Maximum Iterations'); + otherwise + fprintf('Unrecognized Exit Flag'); + end + fprintf('\n'); +end + + +%% ---------------------------------------------------- diff --git a/external/tensor_toolbox_2.5/sshopmc.m b/external/tensor_toolbox_2.5/sshopmc.m new file mode 100755 index 0000000..575f0aa --- /dev/null +++ b/external/tensor_toolbox_2.5/sshopmc.m @@ -0,0 +1,175 @@ +function [lambda,x,flag,its,x0,trace] = sshopmc(A,varargin) +%SSHOPMC Shifted power method for real/complex eigenpair of a real tensor. +% +% [LAMBDA,X]=SSHOPMC(A) finds an eigenvalue (LAMBDA) and eigenvector (X) +% for the real tensor A such that Ax^{m-1} = lambda*x. +% +% [LAMBDA,X]=SSHOPMC(A,parameter,value,...) can specify additional +% parameters as follows: +% +% 'Shift' : Shift in the eigenvalue calculation (Default: 0) +% 'MaxIts' : Maximum power method iterations (Default: 1000) +% 'Start' : Initial guess (Default: normal random vector) +% 'Tol' : Tolerance on norm of change in |lambda| (Default: 1e-16) +% 'Display' : Display every n iterations (Default: -1 for no display) +% +% [LAMBDA,X,FLAG]=SSHOPMC(...) also returns a flag indicating convergence. +% +% FLAG = 0 => Succesfully terminated with |lambda - lambda_old| < Tol +% FLAG = -1 => Norm(X) = 0 +% FLAG = -2 => Maximum iterations exceeded +% +% [LAMBDA,X,FLAG,IT]=SSHOPMC(...) also returns the number of iterations. +% +% [LAMBDA,X,FLAG,IT,X0]=SSHOPMC(...) also returns the intial guess. +% +% [LAMBDA,X,FLAG,IT,X0,TRACE]=SSHOPMC(...) also returns a trace of the +% |lambda| values at each iteration. +% +% REFERENCE: T. G. Kolda and J. R. Mayo, Shifted Power Method for +% Computing Tensor Eigenpairs, SIAM Journal on Matrix Analysis and +% Applications 32(4):1095-1124, October 2011 (doi:10.1137/100801482) +% +% See also SSHOPM, TENSOR, SYMMETRIZE, ISSYMMETRIC. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Error checking on A +P = ndims(A); +N = size(A,1); + +if ~issymmetric(A) + error('Tensor must be symmetric.') +end + +%% Check inputs +p = inputParser; +p.addParamValue('Shift', 0); +p.addParamValue('MaxIts', 1000, @(x) x > 0); +p.addParamValue('Start', [], @(x) isequal(size(x),[N 1])); +p.addParamValue('Tol', 1.0e-16); +p.addParamValue('Display', -1, @isscalar); +p.parse(varargin{:}); + +%% Copy inputs +maxits = p.Results.MaxIts; +x0 = p.Results.Start; +shift = p.Results.Shift; +tol = p.Results.Tol; +display = p.Results.Display; + +%% Check starting vector +if isempty(x0) + x0 = 2*rand(N,1)-1 + 1i * (2*randn(N,1)-1); +end + +if norm(x0) < eps + error('Zero starting vector'); +end + +%% Execute power method +if (display >= 0) + fprintf('TENSOR SHIFTED POWER METHOD: '); + fprintf('Shift = %g\n', shift); + fprintf('---- --------- ----- --------- ----- -------- ----- --------\n'); + fprintf('Iter R(Lambda) Diff C(Lambda) Diff |Lambda| Diff |newx-x|\n'); + fprintf('---- --------- ----- --------- ----- -------- ----- --------\n'); +end + +flag = -2; +x = x0 / norm(x0); +lambda = x'*ttsv(A,x,-1); + +trace = zeros(maxits,1); +trace(1) = lambda; + +for its = 1:maxits + + newx = ttsv(A,x,-1) + shift * x; + newx = newx / (lambda + shift); + + nx = norm(newx); + if nx < eps, + flag = -1; + break; + end + newx = newx / nx; + + newlambda = newx'* ttsv(A,newx,-1); + + if norm(abs(newlambda) - abs(lambda)) < tol + flag = 0; + end + + + if (display > 0) && ((flag == 0) || (mod(its,display) == 0)) + fprintf('%4d ', its); + % Real Part + fprintf('%9.6f ', real(newlambda)); + d = real(newlambda-lambda); + if (d ~= 0) + if (d < 0), c = '-'; else c = '+'; end + fprintf('%ce%+03d ', c, round(log10(abs(d)))); + else + fprintf(' '); + end + % Imaginary Part + fprintf('%9.6f ', imag(newlambda)); + d = imag(newlambda-lambda); + if (d ~= 0) + if (d < 0), c = '-'; else c = '+'; end + fprintf('%ce%+03d ', c, round(log10(abs(d)))); + else + fprintf(' '); + end + % Absolute Value + fprintf('%8.6f ', abs(newlambda)); + d = abs(newlambda) - abs(lambda); + if (d ~= 0) + if (d < 0), c = '-'; else c = '+'; end + fprintf('%ce%+03d ', c, round(log10(abs(d)))); + else + fprintf(' '); + end + % Change in X + fprintf('%8.6f ', norm(newx-x)); + % Line end + fprintf('\n'); + end + + x = newx; + lambda = newlambda; + trace(its+1) = lambda; + + if flag == 0 + break + end +end + +%% Check results +if (display >=0) + switch(flag) + case 0 + fprintf('Successful Convergence'); + case -1 + fprintf('Converged to Zero Vector'); + case -2 + fprintf('Exceeded Maximum Iterations'); + otherwise + fprintf('Unrecognized Exit Flag'); + end + fprintf('\n'); +end + + + diff --git a/external/tensor_toolbox_2.5/tendiag.m b/external/tensor_toolbox_2.5/tendiag.m new file mode 100755 index 0000000..0104e9c --- /dev/null +++ b/external/tensor_toolbox_2.5/tendiag.m @@ -0,0 +1,39 @@ +function X = tendiag(v,sz) +%TENDIAG Creates a tensor with v on the diagonal. +% +% TENDIAG(V) creates a tensor with N dimensions, each of size N, where N +% is the number of elements of V. The elements of V are placed on the +% superdiagonal. +% +% TENDIAG(V,SZ) is the same as above but creates a tensor of size SZ. If +% SZ is not big enough, the tensor will be enlarged to accommodate the +% elements of V on the superdiagonal. +% +% Examples +% X = tendiag([0.1 0.22 0.333]) %<-- creates a 3x3x3 tensor +% +% See also TENSOR, SPTENDIAG. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Make sure v is a column vector +v = reshape(v,[numel(v) 1]); + +N = numel(v); +if ~exist('sz','var') + sz = repmat(N,1,N); +end + +X = tenzeros(sz); +subs = repmat((1:N)', 1, length(sz)); +X(subs) = v; diff --git a/external/tensor_toolbox_2.5/teneye.m b/external/tensor_toolbox_2.5/teneye.m new file mode 100755 index 0000000..a9191b5 --- /dev/null +++ b/external/tensor_toolbox_2.5/teneye.m @@ -0,0 +1,48 @@ +function A = teneye(M,N) +%TENEYE Create identity tensor of specified size. +% +% We say E is the "identity tensor" if TTSV(E,X,-1) = X for all X such +% that NORM(X) = 1. +% +% TENEYE(M,N) returns a (dense) identity tensor of order M and size N. +% The identity tensor only exists when M is even and returns an error +% otherwise. Due to the complexity of generating all possible indices, +% this only works for relatively small M and N (i.e., N <= 7, M <= 6). +% +% Examples +% E = teneye(4,2); %<-- Create 2 x 2 x 2 x 2 identity tensor +% x = rand(2,1); x = x/norm(x); %<-- Generate random x with norm 1 +% norm(ttsv(E,x,-1)-x) %<-- Check that ttsv(E,x,-1) = x +% +% See also tensor, ttsv. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +%% Check that it's an even tensor +if mod(M,2) ~= 0 + error('m must be even'); +end + +%% Generate all possible indices +idx = tt_combinator(N,M,'c','r'); + +%% +A = tenzeros(N*ones(1,M)); +for i = 1:size(idx,1) + p = perms(idx(i,:)); + for j = 1:M/2 + s(:,j) = (p(:,2*j-1) == p(:,2*j)); + end + v = sum(sum(s,2)==M/2); + A(p) = v / factorial(M); +end + diff --git a/external/tensor_toolbox_2.5/tenones.m b/external/tensor_toolbox_2.5/tenones.m new file mode 100755 index 0000000..7472215 --- /dev/null +++ b/external/tensor_toolbox_2.5/tenones.m @@ -0,0 +1,34 @@ +function X = tenones(varargin) +%TENONES Ones tensor. +% +% X = TENONES(SZ) forms a tensor of size SZ with all ones. +% +% TENONES(SZ) is equivalent to TENSOR(ONES(SZ(1),SZ(2),...),SZ). +% +% See also TENSOR, ONES. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if nargin == 1 + sz = varargin{1}; +else + sz = cell2mat(varargin); +end + +if isempty(sz) + X = tensor(); + return; +end + +data = ones([sz 1 1]); +X = tensor(data,sz); diff --git a/external/tensor_toolbox_2.5/tenrand.m b/external/tensor_toolbox_2.5/tenrand.m new file mode 100755 index 0000000..4022224 --- /dev/null +++ b/external/tensor_toolbox_2.5/tenrand.m @@ -0,0 +1,30 @@ +function X = tenrand(varargin) +%TENRAND Uniformly distributed pseudo-random tensor. +% +% X = TENRAND(SZ) forms a tensor of size SZ with pseudo-random +% values drawn from a uniform distribution on the unit interval. +% +% TENRAND(SZ) is equivalent to TENSOR(RAND(SZ(1),SZ(2),...),SZ). +% +% See also TENSOR, SPTENRAND, RAND. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if nargin == 1 + sz = varargin{1}; +else + sz = cell2mat(varargin); +end + +data = rand([sz 1 1]); +X = tensor(data,sz); diff --git a/external/tensor_toolbox_2.5/tensor_toolbox_product_page.html b/external/tensor_toolbox_2.5/tensor_toolbox_product_page.html new file mode 100755 index 0000000..2935683 --- /dev/null +++ b/external/tensor_toolbox_2.5/tensor_toolbox_product_page.html @@ -0,0 +1,228 @@ + + + +MATLAB Tensor Toolbox + + + + + + + + + + + + + + + + + +
Sandia National Laboratories
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +

Tensor Toolbox

+

The MATLAB Tensor Toolbox enables the creation and manipulation of + dense and sparse multidimensional arrays.

+

Documentation

+ + +

Home Page

+

For more information including how to cite the + toolbox (as required by the license), please + visit the Tensor Toolbox homepage at + + http://www.sandia.gov/~tgkolda/TensorToolbox/.

+

Legal Stuff

+ +

Questions or Comments?

+

Please send us + email.

+
+ +

 
Contact
+ Tamara Kolda
+ tgkolda@sandia.gov
+ (925)294-4769

+ +
+ + + + + + + + +
+ diff --git a/external/tensor_toolbox_2.5/tenzeros.m b/external/tensor_toolbox_2.5/tenzeros.m new file mode 100755 index 0000000..037e66c --- /dev/null +++ b/external/tensor_toolbox_2.5/tenzeros.m @@ -0,0 +1,41 @@ +function X = tenzeros(varargin) +%TENZEROS Create zeros tensor. +% +% X = TENZEROS(SZ) forms a tensor of size SZ with all zeros. +% +% TENZEROS(SZ) is equivalent to TENSOR(ZEROS(SZ(1),SZ(2),...),SZ). +% +% See also TENSOR, ZEROS. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if nargin == 1 + sz = varargin{1}; +else + sz = cell2mat(varargin); +end + +if isempty(sz) + X = tensor; + return; +end + +if nargin == 2 + order = sz; + dim = varargin{1}; + sz = dim * ones(1,order); +end + +data = zeros([sz 1 1]); +X = tensor(data,sz); + diff --git a/external/tensor_toolbox_2.5/tt_RandOrthMat.m b/external/tensor_toolbox_2.5/tt_RandOrthMat.m new file mode 100755 index 0000000..3491cb5 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_RandOrthMat.m @@ -0,0 +1,50 @@ +function M=tt_RandOrthMat(n, tol) +%TT_RANDORTHMAT Generates random n x n orthogonal real matrix. +% +% M = RANDORTHMAT(n) +% generates a random n x n orthogonal real matrix. +% +% M = RANDORTHMAT(n,tol) +% explicitly specifies a thresh value that measures linear dependence +% of a newly formed column with the existing columns. Defaults to 1e-6. +% +% In this version the generated matrix distribution *is* uniform over the manifold +% O(n) w.r.t. the induced R^(n^2) Lebesgue measure, at a slight computational +% overhead (randn + normalization, as opposed to rand ). +% +% (c) Ofek Shilon , 2006. +% +%This code is *not* copyrighted by Sandia, but it is distributed with: +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + + + + if nargin==1 + tol=1e-6; + end + + M = zeros(n); % prealloc + + % gram-schmidt on random column vectors + + vi = randn(n,1); + % the n-dimensional normal distribution has spherical symmetry, which implies + % that after normalization the drawn vectors would be uniformly distributed on the + % n-dimensional unit sphere. + + M(:,1) = vi ./ norm(vi); + + for i=2:n + nrm = 0; + while nrm= 2) + type = 'subtensor'; + return; +end + +type = 'subscripts'; + + diff --git a/external/tensor_toolbox_2.5/tt_ccong.m b/external/tensor_toolbox_2.5/tt_ccong.m new file mode 100755 index 0000000..a8cdfb0 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_ccong.m @@ -0,0 +1,27 @@ +function X = tt_ccong(m,n,gamma) +%TT_CCONG Create a random matrix with a fixed congruence +% +% X = TT_CCONG(M,N,GAMMA) creates a matrix X of size M x N such +% that each column of X has norm 1 and any two columns of X have an inner +% product equal to GAMMA. +% +% Based on code from Evrim Acar and the paper G. Tomasi and R. Bro, A +% comparison of algorithms for fitting the PARAFAC model, Computational +% Statistics & Data Analysis, 50: 1700-1734, 2006. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +CG = gamma * ones(n,n) + (1-gamma) * eye(n); +CGR = chol(CG); +X = randn(m,n); +[Q,~] = qr(X,0); +X = Q * CGR; \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/tt_combinator.m b/external/tensor_toolbox_2.5/tt_combinator.m new file mode 100755 index 0000000..5475ac2 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_combinator.m @@ -0,0 +1,392 @@ +function [A] = tt_combinator(N,K,s1,s2) +%TT_COMBINATOR Perform basic permutation and combination samplings. +% COMBINATOR will return one of 4 different samplings on the set 1:N, +% taken K at a time. These samplings are given as follows: +% +% PERMUTATIONS WITH REPETITION/REPLACEMENT +% COMBINATOR(N,K,'p','r') -- N >= 1, K >= 0 +% PERMUTATIONS WITHOUT REPETITION/REPLACEMENT +% COMBINATOR(N,K,'p') -- N >= 1, N >= K >= 0 +% COMBINATIONS WITH REPETITION/REPLACEMENT +% COMBINATOR(N,K,'c','r') -- N >= 1, K >= 0 +% COMBINATIONS WITHOUT REPETITION/REPLACEMENT +% COMBINATOR(N,K,'c') -- N >= 1, N >= K >= 0 +% +% Example: +% +% To see the subset relationships, do this: +% combinator(4,2,'p','r') % Permutations with repetition +% combinator(4,2,'p') % Permutations without repetition +% combinator(4,2,'c','r') % Combinations with repetition +% combinator(4,2,'c') % Combinations without repetition +% +% +% If it is desired to use a set other than 1:N, simply use the output from +% COMBINATOR as an index into the set of interest. For example: +% +% MySet = ['a' 'b' 'c' 'd']; +% MySetperms = combinator(length(MySet),3,'p','r'); % Take 3 at a time. +% MySetperms = MySet(MySetperms) +% +% +% Class support for input N: +% float: double, single +% integers: int8,int16,int32 +% +% +% Notes: +% All of these algorithms have the potential to create VERY large outputs. +% In each subfunction there is an anonymous function which can be used to +% calculate the number of row which will appear in the output. If a rather +% large output is expected, consider using an integer class to conserve +% memory. For example: +% +% M = combinator(int8(30),3,'p','r'); % NOT uint8(30) +% +% will take up 1/8 the memory as passing the 30 as a double. See the note +% below on using the MEX-File. +% +% To make your own code easier to read, the fourth argument can be any +% string. If the string begins with an 'r' (or 'R'), the function +% will be called with the replacement/repetition algorithm. If not, the +% string will be ignored. +% For instance, you could use: 'No replacement', or 'Repetition allowed' +% If only two inputs are used, the function will assume 'p','r'. +% The third argument must begin with either a 'p' or a 'c' but can be any +% string beyond that. +% +% The permutations with repetitions algorithm uses cumsum. So does the +% combinations without repetition algorithm for the special case of K=2. +% Unfortunately, MATLAB does not allow cumsum to work with integer classes. +% Thus a subfunction has been placed at the end for the case when these +% classes are passed. The subfunction will automatically pass the +% necessary matrix to the built-in cumsum when a single or double is used. +% When an integer class is used, the subfunction first looks to see if the +% accompanying MEX-File (cumsumall.cpp) has been compiled. If not, +% then a MATLAB For loop is used to perform the cumsumming. This is +% VERY slow! Therefore it is recommended to compile the MEX-File when +% using integer classes. +% The MEX-File was tested by the author using the Borland 5.5 C++ compiler. +% +% See also, perms, nchoosek, npermutek (on the FEX) +% +% Author: Matt Fig +% Contact: popkenai@yahoo.com +% Date: 5/30/2009 +% +% Reference: http://mathworld.wolfram.com/BallPicking.html +% +%This code is *not* copyrighted by Sandia, but it is distributed with: +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +ng = nargin; + +if ng == 2 + s1 = 'p'; + s2 = 'r'; +elseif ng == 3 + s2 = 'n'; +elseif ng ~= 4 + error('Only 2, 3 or 4 inputs are allowed. See help.') +end + +if isempty(N) || K == 0 + A = []; + return +elseif numel(N)~=1 || N<=0 || ~isreal(N) || floor(N) ~= N + error('N should be one real, positive integer. See help.') +elseif numel(K)~=1 || K<0 || ~isreal(K) || floor(K) ~= K + error('K should be one real non-negative integer. See help.') +end + +STR = lower(s1(1)); % We are only interested in the first letter. + +if ~strcmpi(s2(1),'r') + STR = [STR,'n']; +else + STR = [STR,'r']; +end + +try + switch STR + case 'pr' + A = perms_rep(N,K); % strings + case 'pn' + A = perms_no_rep(N,K); % permutations + case 'cr' + A = combs_rep(N,K); % multichoose + case 'cn' + A = combs_no_rep(N,K); % choose + otherwise + error('Unknown option passed. See help') + end +catch + rethrow(lasterror) % Throw error from here, not subfunction. + % The only error thrown should be K>N for non-replacement calls. +end + + + + +function PR = perms_rep(N,K) +% This is (basically) the same as npermutek found on the FEX. It is the +% fastest way to calculate these (in MATLAB) that I know. +% pr = @(N,K) N^K; Number of rows. +% A speed comparison could be made with COMBN.m, found on the FEX. This +% is an excellent code which uses ndgrid. COMBN is written by Jos. +% +% % All timings represent the best of 4 consecutive runs. +% % All timings shown in subfunction notes used this configuration: +% % 2007a 64-bit, Intel Xeon, win xp 64, 16 GB RAM +% tic,Tc = combinator(single(9),7,'p','r');toc +% %Elapsed time is 0.199397 seconds. Allow Ctrl+T+C+R on block +% tic,Tj = combn(single(1:9),7);toc +% %Elapsed time is 0.934780 seconds. +% isequal(Tc,Tj) % Yes + +if N==1 + PR = ones(1,K,class(N)); + return +elseif K==1 + PR = (1:N).'; + return +end + +CN = class(N); +M = double(N); % Single will give us trouble on indexing. +L = M^K; % This is the number of rows the outputs will have. +PR = zeros(L,K,CN); % Preallocation. +D = ones(1,N-1,CN); % Use this for cumsumming later. +LD = M-1; % See comment on N. +VL = [-(N-1) D].'; % These values will be put into PR. +% Now start building the matrix. +TMP = VL(:,ones(L/M,1,CN)); % Instead of repmatting. +PR(:,K) = TMP(:); % We don't need to do two these in loop. +PR(1:M^(K-1):L,1) = VL; % The first column is the simplest. +% Here we have to build the cols of PR the rest of the way. +for ii = K-1:-1:2 + ROWS = 1:M^(ii-1):L; % Indices into the rows for this col. + TMP = VL(:,ones(length(ROWS)/(LD+1),1,CN)); % Match dimension. + PR(ROWS,K-ii+1) = TMP(:); % Build it up, insert values. +end + +PR(1,:) = 1; % For proper cumsumming. +PR = cumsum2(PR); % This is the time hog. + + + + +function PN = perms_no_rep(N,K) +% Subfunction: permutations without replacement. +% Uses the algorithm in combs_no_rep as a basis, then permutes each row. +% pn = @(N,K) prod(1:N)/(prod(1:(N-K))); Number of rows. + +if N==K + PN = perms_loop(N); % Call helper function. +% [id,id] = sort(PN(:,1)); %#ok Not nec., uncomment for nice order. +% PN = PN(id,:); % Return values. + return +elseif K==1 + PN = (1:N).'; % Easy case. + return +end + +if K>N % Since there is no replacement, this cannot happen. + error(['When no repetitions are allowed, '... + 'K must be less than or equal to N']) +end + +M = double(N); % Single will give us trouble on indexing. +WV = 1:K; % Working vector. +lim = K; % Sets the limit for working index. +inc = 1; % Controls which element of WV is being worked on. +BC = prod(M-K+1:M); % Pre-allocation of return arg. +BC1 = BC / ( prod(1:K)); % Number of comb blocks. +PN = zeros(round(BC),K,class(N)); +L = prod(1:K) ; % To get the size of the blocks. +cnt = 1+L; +P = perms_loop(K); % Only need to use this once. +PN(1:(1+L-1),:) = WV(P); % The first row. + +for ii = 2:(BC1 - 1); + if logical((inc+lim)-N) % The logical is nec. for class single(?) + stp = inc; % This is where the for loop below stops. + flg = 0; % Used for resetting inc. + else + stp = 1; + flg = 1; + end + + for jj = 1:stp + WV(K + jj - inc) = lim + jj; % Faster than a vector assignment! + end + + PN(cnt:(cnt+L-1),:) = WV(P); % Assign block. + cnt = cnt + L; % Increment base index. + inc = inc*flg + 1; % Increment the counter. + lim = WV(K - inc + 1 ); % lim for next run. +end + +V = (N-K+1):N; % Final vector. +PN(cnt:(cnt+L-1),:) = V(P); % Fill final block. +% The sorting below is NOT necessary. If you prefer this nice +% order, the next two lines can be un-commented. +% [id,id] = sort(PN(:,1)); %#ok This is not necessary! +% PN = PN(id,:); % Return values. + + + + +function P = perms_loop(N) +% Helper function to perms_no_rep. This is basically the same as the +% MATLAB function perms. It has been un-recursed for a runtime of around +% half the recursive version found in perms.m For example: +% +% tic,Tp = perms(1:9);toc +% %Elapsed time is 0.222111 seconds. Allow Ctrl+T+C+R on block +% tic,Tc = combinator(9,9,'p');toc +% %Elapsed time is 0.143219 seconds. +% isequal(Tc,Tp) % Yes + +M = double(N); % Single will give us trouble on indexing. +P = 1; % Initializer. +G = cumprod(1:(M-1)); % Holds the sizes of P. +CN = class(N); + +for n = 2:M + q = P; + m = G(n-1); + P = zeros(n*m,n,CN); + P(1:m, 1) = n; + P(1:m, 2:n) = q; + a = m + 1; + + for ii = n-1:-1:1, + t = q; + t(t == ii) = n; + b = a + m - 1; + P(a:b, 1) = ii; + P(a:b, 2:n) = t; + a = b + 1; + end +end + + + + +function CR = combs_rep(N,K) +% Subfunction multichoose: combinations with replacement. +% cr = @(N,K) prod((N):(N+K-1))/(prod(1:K)); Number of rows. + +M = double(N); % Single will give us trouble on indexing. +WV = ones(1,K,class(N)); % This is the working vector. +mch = prod((M:(M+K-1)) ./ (1:K)); % Pre-allocation. +CR = ones(round(mch),K,class(N)); + +for ii = 2:mch + if WV(K) == N + cnt = K-1; % Work backwards in WV. + + while WV(cnt) == N + cnt = cnt-1; % Work backwards in WV. + end + + WV(cnt:K) = WV(cnt) + 1; % Fill forward. + else + WV(K) = WV(K)+1; % Keep working in this group. + end + + CR(ii,:) = WV; +end + + + + +function CN = combs_no_rep(N,K) +% Subfunction choose: combinations w/o replacement. +% cn = @(N,K) prod(N-K+1:N)/(prod(1:K)); Number of rows. +% Same output as the MATLAB function nchoosek(1:N,K), but often faster for +% larger N. +% For example: +% +% tic,Tn = nchoosek(1:17,8);toc +% %Elapsed time is 0.430216 seconds. Allow Ctrl+T+C+R on block +% tic,Tc = combinator(17,8,'c');toc +% %Elapsed time is 0.024438 seconds. +% isequal(Tc,Tn) % Yes + +if K>N + error(['When no repetitions are allowed, '... + 'K must be less than or equal to N']) +end + +M = double(N); % Single will give us trouble on indexing. + +if K == 1 + CN =(1:N).'; % These are simple cases. + return +elseif K == N + CN = (1:N); + return +elseif K==2 && N>2 % This is an easy case to do quickly. + BC = (M-1)*M / 2; + id1 = cumsum2((M-1):-1:2)+1; + CN = zeros(BC,2,class(N)); + CN(:,2) = 1; + CN(1,:) = [1 2]; + CN(id1,1) = 1; + CN(id1,2) = -((N-3):-1:0); + CN = cumsum2(CN); + return +end + +WV = 1:K; % Working vector. +lim = K; % Sets the limit for working index. +inc = 1; % Controls which element of WV is being worked on. +BC = prod(M-K+1:M) / (prod(1:K)); % Pre-allocation. +CN = zeros(round(BC),K,class(N)); +CN(1,:) = WV; % The first row. + +for ii = 2:(BC - 1); + if logical((inc+lim)-N) % The logical is nec. for class single(?) + stp = inc; % This is where the for loop below stops. + flg = 0; % Used for resetting inc. + else + stp = 1; + flg = 1; + end + + for jj = 1:stp + WV(K + jj - inc) = lim + jj; % Faster than a vector assignment. + end + + CN(ii,:) = WV; % Make assignment. + inc = inc*flg + 1; % Increment the counter. + lim = WV(K - inc + 1 ); % lim for next run. +end + +CN(ii+1,:) = (N-K+1):N; + + + + +function A = cumsum2(A) +%CUMSUM2, works with integer classes. +% Duplicates the action of cumsum, but for integer classes. +% If Matlab ever allows cumsum to work for integer classes, we can remove +% this. + +if isfloat(A) + A = cumsum(A); % For single and double, use built-in. + return +else + try + A = cumsumall(A); % User has the MEX-File ready? + catch + warning('Cumsumming by loop. MEX cumsumall.cpp for speed.') %#ok + for ii = 2:size(A,1) + A(ii,:) = A(ii,:) + A(ii-1,:); % User likes it slow. + end + end +end diff --git a/external/tensor_toolbox_2.5/tt_cp_fg.m b/external/tensor_toolbox_2.5/tt_cp_fg.m new file mode 100755 index 0000000..8c173a3 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_cp_fg.m @@ -0,0 +1,88 @@ +function [f,G] = tt_cp_fg(Z,A,Znormsqr) +%TT_CP_FG Computes function and gradient of the CP function. +% +% [F,G] = TT_CP_FG(Z,A) calculates F = (1/2) ||Z - ktensor(A)||^2 where +% Z is an N-way tensor and A is a ktensor or a cell array with N +% factor matrices. It also calculates the gradient of the CP fit +% function where Z is an N-way tensor and A is a ktensor or a +% cell array with N factor matrices. The result is also a cell +% array with N factor matrices corresponding to the gradients; in +% other words, G{n}(:,r) is the partial derivative of the fit +% function with respect to A{n}(:,r). +% +% [F,G] = TT_CP_FG(Z,A,NORMZSQR) also passes in the pre-computed +% norm of Z, which makes the computations faster. +% +% See also CP_OPT, TT_CP_FUN. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + + +%% Set-up +if ~isa(Z,'tensor') && ~isa(Z,'sptensor') + error('Z must be a tensor or a sptensor'); +end +N = ndims(Z); + +if ~iscell(A) && ~isa(A,'ktensor'); + error('A must be a cell array or ktensor'); +end + +if isa(A,'ktensor') + A = tocell(A); +end +R = size(A{1},2); + +%% Upsilon and Gamma +Upsilon = cell(N,1); +for n = 1:N + Upsilon{n} = A{n}'*A{n}; +end + +Gamma = cell(N,1); +for n = 1:N + Gamma{n} = ones(R,R); + for m = [1:n-1,n+1:N] + Gamma{n} = Gamma{n} .* Upsilon{m}; + end +end + + +%% Calculation + +%F1 +if exist('Znormsqr','var') + f_1 = Znormsqr; +else + f_1 = norm(Z)^2; +end + +%% Calculate gradient and F2 +G = cell(N,1); +U = mttkrp(Z,A,1); +V = A{1} .* U; +f_2 = sum(V(:)); +G{1} = -U + A{1}*Gamma{1}; +for n = 2:N + U = mttkrp(Z,A,n); + G{n} = -U + A{n}*Gamma{n}; +end + +%F3 +W = Gamma{1} .* Upsilon{1}; +f_3 = sum(W(:)); + +%SUM +f = 0.5 * f_1 - f_2 + 0.5 * f_3; + + diff --git a/external/tensor_toolbox_2.5/tt_cp_fun.m b/external/tensor_toolbox_2.5/tt_cp_fun.m new file mode 100755 index 0000000..1410f38 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_cp_fun.m @@ -0,0 +1,30 @@ +function [f,g] = tt_cp_fun(x,Z,Znormsqr) +%TT_CP_FUN Calculate function and gradient for CP fit function. +% +% [F,G] = TT_CP_FUN(X,Z) where X is a vector containing the entries of the +% components of the model and Z is the tensor to be fit. +% +% See also TT_CP_VEC_TO_FAC, TT_FAC_TO_VEC, TT_CP_FG, CP_OPT +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Convert x to a cell array of matrices +A = tt_cp_vec_to_fac(x,Z); + +%% Call cp_fit and cp_gradient using cp_fg +[f,G] = tt_cp_fg(Z,A,Znormsqr); + +%% Convert a cell array to a vector +g = tt_fac_to_vec(G); + + diff --git a/external/tensor_toolbox_2.5/tt_cp_vec_to_fac.m b/external/tensor_toolbox_2.5/tt_cp_vec_to_fac.m new file mode 100755 index 0000000..7f00cb3 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_cp_vec_to_fac.m @@ -0,0 +1,35 @@ +function A = cp_vec_to_fac(x,Z) +%CP_VEC_TO_FAC Converts a vector to a cell array of factor matrices. +% +% A = CP_VEC_TO_FAC(X,Z) converts the vector X into a cell array +% of factor matrices consistent with the size of the tensor Z. +% +% See also FAC_TO_VEC, CP_FUN, CP_OPT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Set-up +P = length(x); +N = ndims(Z); +sz = size(Z); + +%% Determine R +R = P / sum(sz); + +%% Create A +A = cell(N,1); +for n = 1:N + idx1 = sum(sz(1:n-1))*R + 1; + idx2 = sum(sz(1:n))*R; + A{n} = reshape(x(idx1:idx2),sz(n),R); +end \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/tt_cp_wfg.m b/external/tensor_toolbox_2.5/tt_cp_wfg.m new file mode 100755 index 0000000..ed623d8 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_cp_wfg.m @@ -0,0 +1,53 @@ +function [f,G] = tt_cp_wfg(Z,W,A,normZsqr) +%TT_CP_WFG Function and gradient of CP with missing data. +% +% [F,G] = TT_CP_WFG(Z,W,A) computes the function and gradient values of +% the function 0.5 * || W .* (Z - ktensor(A)) ||^2. The input A is a +% cell array containing the factor matrices. The input W is a (dense +% or sparse) tensor containing zeros wherever data is missing. The +% input Z is a (dense or sparse) tensor that is assumed to have +% zeros wherever there is missing data. The output is the function F +% and a cell array G containing the partial derivatives with respect +% to the factor matrices. +% +% [F,G] = TT_CP_WFG(Z,W,A,NORMZSQR) also passes in the pre-computed +% norm of Z, which makes the computations faster. +% +% See also TT_CP_WFUN, TT_CP_WFG_SPARSE, TT_CP_WFG_SPARSE_SETUP. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Compute B = W.*ktensor(A) +if isa(W,'sptensor') + B = W.*ktensor(A); +else + B = W.*full(ktensor(A)); +end + +%% Compute normZ +if ~exist('normZsqr','var') + normZsqr = norm(Z)^2; +end + +% function value +f = 0.5 * normZsqr - innerprod(Z,B) + 0.5 * norm(B)^2; + +% gradient computation +N = ndims(Z); +G = cell(N,1); +T = Z - B; +for n = 1:N + G{n} = zeros(size(A{n})); + G{n} = -mttkrp(T,A,n); +end + diff --git a/external/tensor_toolbox_2.5/tt_cp_wfg_sparse.m b/external/tensor_toolbox_2.5/tt_cp_wfg_sparse.m new file mode 100755 index 0000000..057924a --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_cp_wfg_sparse.m @@ -0,0 +1,99 @@ +function [f,G] = tt_cp_wfg_sparse(Zvals,W,A,normZsqr,memflag) +%TT_CP_WFG_SPARSE Computes weighted CP function and gradient. +% +% [F,G] = TT_CP_WFG_SPARSE(ZVALS,W,A) computes the function and +% gradient with respect to A of || W .* (Z - ktensor(A)) ||^2 where +% Z = W .* X. The variable ZVALS contains the values of the tensor Z +% at the locations specified by W.subs. (ZVALS can be computed using +% a provided preprocessing function.) The variable A is a cell array +% of component matrices. The tensor W is a sparse tensor that has +% ones in entries where we know the values. +% +% [F,G] = TT_CP_WFG_SPARSE(ZVALS,W,A,NORMZSQR) also passes in the +% pre-computed norm of Z, which makes the computations faster. +% +% [F,G] = TT_CP_WFG_SPARSE(ZVALS,A,W,NORMZSQR,false) uses less memory +% but more time and is appropriate for very large sparse tensors. +% +% See also TT_CP_WFG_SPARSE_SETUP, CP_WFG, CP_WFUN. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Set-up +N = ndims(W); +R = size(A{1},2); +sz = cellfun(@(x)size(x,1),A); +Wsubs = W.subs; +Wvals = W.vals; +Nvals = length(Wvals); + +if ~exist('memflag','var') + memflag = true; +end + +%% Compute B = W.*ktensor(A) +Bvals = zeros(Nvals,1); +for r = 1:R + newvals = Wvals; + for n = 1:N + bigArn = A{n}(Wsubs(:,n),r); + newvals = newvals .* bigArn; + end + Bvals = Bvals + newvals; +end + +%% Compute normZ +if ~exist('normZsqr','var') + normZsqr = sum(Zvals.^2); +end + +%% function value: f = 0.5 * normZsqr - innerprod(Z,B) + 0.5 * norm(B)^2 +f = 0.5 * normZsqr - Zvals'*Bvals + 0.5 * sum(Bvals.^2); + +%% gradient computation +Tvals = Zvals - Bvals; + +G = cell(N,1); +for n = 1:N + G{n} = zeros(size(A{n})); +end + +for r = 1:R + if (memflag) + bigAr = cell(N,1); + for n = 1:N + bigAr{n} = A{n}(Wsubs(:,n),r); + end + for SkipN = 1:N + newvals = Tvals; + for n = [1:SkipN-1,SkipN+1:N] + newvals = newvals .* bigAr{n}; + end + G{SkipN}(:,r) = accumarray(Wsubs(:,SkipN),newvals,[sz(SkipN) 1]); + end + else + for SkipN = 1:N + newvals = Tvals; + for n = [1:SkipN-1,SkipN+1:N] + bigArn = A{n}(Wsubs(:,n),r); + newvals = newvals .* bigArn; + end + G{SkipN}(:,r) = accumarray(Wsubs(:,SkipN),newvals,[sz(SkipN) 1]); + end + end + +end + +for n = 1:N + G{n} = -G{n}; +end diff --git a/external/tensor_toolbox_2.5/tt_cp_wfg_sparse_setup.m b/external/tensor_toolbox_2.5/tt_cp_wfg_sparse_setup.m new file mode 100755 index 0000000..7b413d1 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_cp_wfg_sparse_setup.m @@ -0,0 +1,26 @@ +function Zvals = cp_wfg_sparse_setup(Z,W) +%CP_WFG_SPARSE_SETUP Creates a special array. +% +% ZVALS = CP_WFG_SPARSE_SETUP(Z,W) creates an array ZVALS that +% contains the values of Z corresponding to the indices specified +% by W.subs. +% +% See also CP_WFG_SPARSE. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +Zsubs = Z.subs; +Wsubs = W.subs; +Zvals = zeros(size(W.vals)); +[junk,loc] = ismember(Zsubs,Wsubs,'rows'); +Zvals(loc) = Z.vals; diff --git a/external/tensor_toolbox_2.5/tt_cp_wfun.m b/external/tensor_toolbox_2.5/tt_cp_wfun.m new file mode 100755 index 0000000..6b8f66b --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_cp_wfun.m @@ -0,0 +1,58 @@ +function [f,g] = tt_cp_wfun(Zdata,W,x,normZsqr,memflag) +%TT_CP_WFUN Computes function and gradient for weighted CP. +% +% [F,G] = TT_CP_WFUN(Z,W,x,normZsqr) calculates the function and gradient +% for the function 0.5 * || W .* (Z - ktensor(A)) ||^2 where W is an +% indicator for missing data (0 = missing, 1 = present), Z is the data +% tensor that is being fit (assumed that missing entries have already +% been set to zero), A is a cell array of factor matrices that is created +% from the vector x, and normZsqr in the norm of Z squared. +% +% [F,G] = TT_CP_WFUN(Zvals,W,x,normZsqr) is a special version that takes +% just the nonzeros in Z as calculated by the helper function +% CP_WFG_SPARSE_SETUP. +% +% [F,G] = TT_CP_WFUN(....,false) uses a more memory efficient version for +% the sparse code. +% +% See also TT_CP_WFG, TT_CP_WFG_SPARSE, TT_CP_WFG_SPARSE_SETUP +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Convert x to factor matrices (i.e., a cell array). +% Normally we would pass in the data tensor, but we may have a data +% tensor or a data array if we are doing the sparse +% calculation. Therefore, we exploit the fact that W is the same +% size as Z and pass it into the function. +A = tt_cp_vec_to_fac(x,W); + +%% Compute the function and gradient +if isa(Zdata,'tensor') || isa(Zdata,'sptensor') + if ~exist('normZsqr','var') + normZsqr = norm(Zdata)^2; + end + [f,G] = tt_cp_wfg(Zdata,W,A,normZsqr); +else + if ~exist('normZsqr','var') + normZsqr = sum(Zdata.^2); + end + if ~exist('memflag','var') + memflag = true; + end + [f,G] = tt_cp_wfg_sparse(Zdata,W,A,normZsqr,memflag); +end + +%% Convert gradient to a vector +g = tt_fac_to_vec(G); + + diff --git a/external/tensor_toolbox_2.5/tt_create_missing_data_pattern.m b/external/tensor_toolbox_2.5/tt_create_missing_data_pattern.m new file mode 100755 index 0000000..bd235f2 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_create_missing_data_pattern.m @@ -0,0 +1,82 @@ +function W = create_missing_data_pattern(sz,M,isSparse) +%TEST_CREATE_RME Creates a randomly missing element (RME) indicator tensor. +% +% W = TEST_CREATE_RME(SZ,M) creates an indicator (binary) tensor W of the +% specified size with 0's indicating missing data and 1's indicating +% valid data. The percentage of zeros is given by M. Will only return a +% tensor that has at least one entry per N-1 dimensional slice. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +% Code by Evrim Acar and Tammy Kolda, 2009. + +%% Set up isSparse variable +if ~exist('isSparse','var') + isSparse = false; +end + +%% Initialize +% Number of dimensions +N = length(sz); + +% Total number of entries in tensor of given sz +P = prod(sz); + +% Total number of entries that should be set to one +Q = ceil((1-M)*P); + +%% Create the tensor +% Keep iterating until the tensor is created or we give up. +for iter = 1:20 + % Create the indicator tensor W + if isSparse + % start with 50% more than Q random subs + % TODO: work out the expected value of a*Q to guarantee Q unique entries + subs = unique(ceil(rand(ceil(1.5*Q),size(sz,2))*diag(sz)),'rows'); + % check if there are too many unique subs + if size(subs,1) > Q + % unique orders the subs and would bias toward first subs + % with lower values, so we sample to cut back + idx = randperm(size(subs,1)); + subs = subs(idx(1:Q),:); + elseif size(subs,1) < Q + warning('Only generated %d of %d desired subscripts', size(subs,1), Q); + end + W = sptensor(subs,1,sz); + else + % Compute the linear indices of the missing entries. Note that + % the indices must be a column array for the linear indexing + % into W to work. + idx = randperm(P); + idx = idx(1:Q)'; + W = tenzeros(sz); + W(idx) = 1; + end + + % Check if W has any empty slices + isokay = zeros(N,1); + for n = 1:N + isokay(n) = all(double(collapse(W,-n))); + end + + % Quit if we're okay + if all(isokay) + break; + end + +end + +if ~all(isokay) + error('After %d iterations, cannot produce a tensor with %f%% missing data without an empty slice.', iter, M*100); +end + + \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/tt_dimscheck.m b/external/tensor_toolbox_2.5/tt_dimscheck.m new file mode 100755 index 0000000..0580e41 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_dimscheck.m @@ -0,0 +1,78 @@ +function [sdims,vidx] = tt_dimscheck(dims,N,M) +%TT_DIMSCHECK Used to preprocess dimensions tensor dimensions. +% +% NEWDIMS = TT_DIMCHECK(DIMS,N) checks that the specified dimensions +% are valid for a tensor of order N. If DIMS is empty, then +% NEWDIMS=1:N. If DIMS is negative, then NEWDIMS is everything +% but the dimensions specified by -DIMS. Finally, NEWDIMS is +% returned in sorted order. +% +% [NEWDIMS,IDX] = TT_DIMCHECK(DIMS,N,M) does all of the above but +% also returns an index for M muliplicands. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Fix empty case +if isempty(dims) + dims = 1:N; +end + +% Fix "minus" case +if (max(dims) < 0) + % Check that every member of dims is in 1:N + tf = ismember(-dims,1:N); + if min(tf) == 0 + error('Invalid dimensions specified'); + end + dims = setdiff(1:N, -dims); +end + +% Check that every member of dims is in 1:N +tf = ismember(dims,1:N); +if min(tf) == 0 + error('Invalid dimensions specified'); +end + +% Save the number of dimensions in dims +P = length(dims); + +% Reorder dims from smallest to largest (this matters in particular +% for the vector multiplicand case, where the order affects the +% result) +[sdims,sidx] = sort(dims,'ascend'); + +if (nargout == 2) + % Can't have more multiplicands them dimensions + if (M > N) + error('Cannot have more multiplcands than dimensions'); + end + + % Check that the number of mutliplicands must either be + % full-dimensional (i.e., M==N) or equal to the number of specified + % dimensions (i.e., M==P). + if (M ~= N) && (M ~= P) + error('Invalid number of multiplicands'); + end + + % Check sizes to determine how to index multiplicands + if (P == M) + % Case 1: Number of items in dims and number of multiplicands + % are equal; therefore, index in order of how sdims was sorted. + vidx = sidx; + else + % Case 2: Number of multiplicands is equal to the number of + % dimensions in the tensor; therefore, index multiplicands by + % dimensions specified in dims argument. + vidx = sdims; % index multiplicands by (sorted) dimension + end +end diff --git a/external/tensor_toolbox_2.5/tt_fac_to_vec.m b/external/tensor_toolbox_2.5/tt_fac_to_vec.m new file mode 100755 index 0000000..7cecf88 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_fac_to_vec.m @@ -0,0 +1,38 @@ +function x = fac_to_vec(A) +%FAC_TO_VEC Converts a set of factor matrices to a vector. +% +% X = FAC_TO_VEC(A) converts a cell array of factor matrices A to a +% vector by vectorizing each matrix and stacking them. +% +% See also CP_VEC_TO_FAC, CP_FUN, CP_OPT. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +%% Set-up +N = length(A); + +%% Get sizes +sz = zeros(N,1); +for n = 1:N + sz(n) = size(A{n},1); +end +R = size(A{1},2); +P = sum(sz)*R; + +%% Create x +x = zeros(P,1); +for n = 1:N + idx1 = sum(sz(1:n-1))*R + 1; + idx2 = sum(sz(1:n))*R; + x(idx1:idx2) = reshape(A{n},sz(n)*R,1); +end \ No newline at end of file diff --git a/external/tensor_toolbox_2.5/tt_ind2sub.m b/external/tensor_toolbox_2.5/tt_ind2sub.m new file mode 100755 index 0000000..8b76b27 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_ind2sub.m @@ -0,0 +1,32 @@ +function subs = tt_ind2sub(siz,idx) +%TT_IND2SUB Multiple subscripts from linear indices. +% +% SUBS = TT_IND2SUB(SIZ,INDS) returns that subscripts equivalent +% to the linear indices in INDS for a tensor of size SIZ. +% +% See also TT_SUB2IND, IND2SUB. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(idx) + subs = []; + return; +end + +k = [1 cumprod(siz(1:end-1))]; +n = length(siz); +idx = idx - 1; +for i = n : -1 : 1 + subs(:,i) = floor(idx / k(i)) + 1; + idx = rem(idx,k(i)); +end diff --git a/external/tensor_toolbox_2.5/tt_intvec2str.m b/external/tensor_toolbox_2.5/tt_intvec2str.m new file mode 100755 index 0000000..f285078 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_intvec2str.m @@ -0,0 +1,21 @@ +function s = tt_intvec2str(v) +%TT_VEC2STR Print integer vector to a string with brackets. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(v) + s = sprintf('[]'); + return; +end + +s = ['[ ' sprintf('%d ',v(1:end)) ']']; diff --git a/external/tensor_toolbox_2.5/tt_loglikelihood.m b/external/tensor_toolbox_2.5/tt_loglikelihood.m new file mode 100755 index 0000000..9a41791 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_loglikelihood.m @@ -0,0 +1,41 @@ +function f = tt_loglikelihood(X,M) +%TT_LOGLIKELIHOOD Compute log-likelihood of data X with model M. +% +% F = TT_LOGLIKELIHOOD(X,M) computes the log-likelihood of model M given +% data X, where M is a ktensor and X is a tensor or sptensor. +% Specifically, F = - (sum_i m_i - x_i * log_i) where i is a multiindex +% across all tensor dimensions. +% +% See also cp_apr, tensor, sptensor, ktensor. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +N = ndims(X); + +if ~isa(M, 'ktensor') + error('M must be a ktensor'); +end + +M = normalize(M,1,1); + +if isa(X, 'sptensor') + xsubs = X.subs; + A = M.U{1}(xsubs(:,1),:); + for n = 2:N + A = A .* M.U{n}(xsubs(:,n),:); + end + f = sum(X.vals .* log(sum(A,2))) - sum(sum(M.U{1})); +else + f = sum(sum(double(tenmat(X,1)) .* log(double(tenmat(M,1))))) - sum(sum(M.U{1})); +end + + diff --git a/external/tensor_toolbox_2.5/tt_matrix2cellstr.m b/external/tensor_toolbox_2.5/tt_matrix2cellstr.m new file mode 100755 index 0000000..39c0321 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_matrix2cellstr.m @@ -0,0 +1,22 @@ +function S = tt_matrix2cellstr(M) +%TT_MATRIX2CELLSTR Convert a matrix to a cell array of strings. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +fmt = get(0,'FormatSpacing'); +format compact +S = evalc('disp(M)'); +set(0,'FormatSpacing',fmt) +S = textscan(S,'%s','delimiter','\n','whitespace',''); +S = S{1}; +end diff --git a/external/tensor_toolbox_2.5/tt_size2str.m b/external/tensor_toolbox_2.5/tt_size2str.m new file mode 100755 index 0000000..b09c564 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_size2str.m @@ -0,0 +1,26 @@ +function s = tt_size2str(sz) +%TT_SIZE2STR Convert size to a string that can be printed. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(sz) + s = sprintf('[empty tensor]'); + return; +end + +if numel(sz) == 1 + s = sprintf('%d',sz); +else + s = [sprintf('%d x ',sz(1:end-1)) sprintf('%d', sz(end)) ]; +end + diff --git a/external/tensor_toolbox_2.5/tt_sizecheck.m b/external/tensor_toolbox_2.5/tt_sizecheck.m new file mode 100755 index 0000000..18c83b2 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_sizecheck.m @@ -0,0 +1,35 @@ +function ok = tt_sizecheck(siz) +%TT_SIZECHECK Checks that the size is valid. +% +% TT_SIZECHECK(S) throws an error if S is not a valid size array, +% which means that it is a row vector with strictly postitive, +% real-valued, finite integer values. +% +% X = TT_SIZECHECK(S) returns true if S is a valid and false otherwise. +% +% See also TT_SUBSCHECK. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if ndims(siz) == 2 && size(siz,1) == 1 ... + && isreal(siz) ... + && ~any(isnan(siz(:))) && ~any(isinf(siz(:))) ... + && isequal(siz,round(siz)) && all(siz(:) > 0) + ok = true; +else + ok = false; +end + +if ~ok && nargout == 0 + error('Size must be a row vector of real positive integers'); +end diff --git a/external/tensor_toolbox_2.5/tt_sub2ind.m b/external/tensor_toolbox_2.5/tt_sub2ind.m new file mode 100755 index 0000000..6db7675 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_sub2ind.m @@ -0,0 +1,29 @@ +function idx = tt_sub2ind(siz,subs) +%TT_SUB2IND Converts multidimensional subscripts to linear indices. +% +% INDS = TT_SUB2IND(SIZ,SUBS) returns the linear indices +% equivalent to the subscripts in the array SUBS for a tensor of +% size SIZ. +% +% See also TT_IND2SUB, SUB2IND. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(subs) + idx = []; + return; +end + +mult = [1 cumprod(siz(1:end-1))]; +idx = (subs - 1) * mult' + 1; + diff --git a/external/tensor_toolbox_2.5/tt_subscheck.m b/external/tensor_toolbox_2.5/tt_subscheck.m new file mode 100755 index 0000000..e2c79b2 --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_subscheck.m @@ -0,0 +1,39 @@ +function ok = tt_subscheck(subs) +%TT_SUBSCHECK Checks for valid subscripts. +% +% TT_SUBSCHECK(S) throws an error if S is not a valid subscript +% array, which means that S is a matrix of real-valued, finite, +% positive, integer subscripts. +% +% X = TT_SUBSCHECK(S) returns true if S is a valid and false +% otherwise. +% +% See also TT_SIZECHECK, TT_VALSCHECK. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + +% +% Includes improvements offered by Marcus Brubaker. + +if isempty(subs) + ok = true; +elseif ndims(subs) == 2 && isreal(subs) ... + && all(isfinite(subs(:)) & subs(:) > 0) ... + && isequal(subs,round(subs)) + ok = true; +else + ok = false; +end + +if ~ok && nargout == 0 + error('Subscripts must be a matrix of real positive integers'); +end diff --git a/external/tensor_toolbox_2.5/tt_subsubsref.m b/external/tensor_toolbox_2.5/tt_subsubsref.m new file mode 100755 index 0000000..34608fd --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_subsubsref.m @@ -0,0 +1,21 @@ +function a = tt_subsubsref(obj,s) +%TT_SUBSUBSREF Helper function for tensor toolbox subsref. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if length(s) == 1 + a = obj; +else + a = subsref(obj, s(2:end)); +end + diff --git a/external/tensor_toolbox_2.5/tt_valscheck.m b/external/tensor_toolbox_2.5/tt_valscheck.m new file mode 100755 index 0000000..fa10b7b --- /dev/null +++ b/external/tensor_toolbox_2.5/tt_valscheck.m @@ -0,0 +1,31 @@ +function ok = tt_valscheck(vals) +%TT_VALSCHECK Checks for valid values. +% +% TT_VALSCHECK(S) throws an error if S is not a valid values +% array, which means that S is a column array. +% +% X = TT_VALSCHECK(S) returns true if S is a valid and false otherwise. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +if isempty(vals) + ok = true; +elseif ndims(vals) == 2 && size(vals,2) == 1 + ok = true; +else + ok = false; +end + +if ~ok && nargout == 0 + error('Values must be a column array'); +end diff --git a/external/tensor_toolbox_2.5/tucker_als.m b/external/tensor_toolbox_2.5/tucker_als.m new file mode 100755 index 0000000..b240cdb --- /dev/null +++ b/external/tensor_toolbox_2.5/tucker_als.m @@ -0,0 +1,158 @@ +function [T,Uinit] = tucker_als(X,R,varargin) +%TUCKER_ALS Higher-order orthogonal iteration. +% +% T = TUCKER_ALS(X,R) computes the best rank-(R1,R2,..,Rn) +% approximation of tensor X, according to the specified dimensions +% in vector R. The input X can be a tensor, sptensor, ktensor, or +% ttensor. The result returned in T is a ttensor. +% +% T = TUCKER_ALS(X,R,'param',value,...) specifies optional parameters and +% values. Valid parameters and their default values are: +% 'tol' - Tolerance on difference in fit {1.0e-4} +% 'maxiters' - Maximum number of iterations {50} +% 'dimorder' - Order to loop through dimensions {1:ndims(A)} +% 'init' - Initial guess [{'random'}|'nvecs'|cell array] +% 'printitn' - Print fit every n iterations {1} +% +% [T,U0] = TUCKER_ALS(...) also returns the initial guess. +% +% Examples: +% X = sptenrand([5 4 3], 10); +% T = tucker_als(X,2); %<-- best rank(2,2,2) approximation +% T = tucker_als(X,[2 2 1]); %<-- best rank(2,2,1) approximation +% T = tucker_als(X,2,'dimorder',[3 2 1]); +% T = tucker_als(X,2,'dimorder',[3 2 1],'init','nvecs'); +% U0 = {rand(5,2),rand(4,2),[]}; %<-- Initial guess for factors of T +% T = tucker_als(X,2,'dimorder',[3 2 1],'init',U0); +% +% See also TTENSOR, TENSOR, SPTENSOR, KTENSOR. +% +%MATLAB Tensor Toolbox. +%Copyright 2012, Sandia Corporation. + +% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others. +% http://www.sandia.gov/~tgkolda/TensorToolbox. +% Copyright (2012) Sandia Corporation. Under the terms of Contract +% DE-AC04-94AL85000, there is a non-exclusive license for use of this +% work by or on behalf of the U.S. Government. Export of this data may +% require a license from the United States Government. +% The full license terms can be found in the file LICENSE.txt + + +% Extract number of dimensions and norm of X. +N = ndims(X); +normX = norm(X); + +%% Set algorithm parameters from input or by using defaults +params = inputParser; +params.addParamValue('tol',1e-4,@isscalar); +params.addParamValue('maxiters',50,@(x) isscalar(x) & x > 0); +params.addParamValue('dimorder',1:N,@(x) isequal(sort(x),1:N)); +params.addParamValue('init', 'random', @(x) (iscell(x) || ismember(x,{'random','nvecs','eigs'}))); +params.addParamValue('printitn',1,@isscalar); +params.parse(varargin{:}); + +%% Copy from params object +fitchangetol = params.Results.tol; +maxiters = params.Results.maxiters; +dimorder = params.Results.dimorder; +init = params.Results.init; +printitn = params.Results.printitn; + +if numel(R) == 1 + R = R * ones(N,1); +end +U = cell(N,1); + +%% Error checking +% Error checking on maxiters +if maxiters < 0 + error('OPTS.maxiters must be positive'); +end + +% Error checking on dimorder +if ~isequal(1:N,sort(dimorder)) + error('OPTS.dimorder must include all elements from 1 to ndims(X)'); +end + +%% Set up and error checking on initial guess for U. +if iscell(init) + Uinit = init; + if numel(Uinit) ~= N + error('OPTS.init does not have %d cells',N); + end + for n = dimorder(2:end); + if ~isequal(size(Uinit{n}),[size(X,n) R(n)]) + error('OPTS.init{%d} is the wrong size',n); + end + end +else + % Observe that we don't need to calculate an initial guess for the + % first index in dimorder because that will be solved for in the first + % inner iteration. + if strcmp(init,'random') + Uinit = cell(N,1); + for n = dimorder(2:end) + Uinit{n} = rand(size(X,n),R(n)); + end + elseif strcmp(init,'nvecs') || strcmp(init,'eigs') + % Compute an orthonormal basis for the dominant + % Rn-dimensional left singular subspace of + % X_(n) (1 <= n <= N). + Uinit = cell(N,1); + for n = dimorder(2:end) + fprintf(' Computing %d leading e-vectors for factor %d.\n', ... + R(n),n); + Uinit{n} = nvecs(X,n,R(n)); + end + else + error('The selected initialization method is not supported'); + end +end + +%% Set up for iterations - initializing U and the fit. +U = Uinit; +fit = 0; + +if printitn > 0 + fprintf('\nTucker Alternating Least-Squares:\n'); +end + +%% Main Loop: Iterate until convergence +for iter = 1:maxiters + + fitold = fit; + + % Iterate over all N modes of the tensor + for n = dimorder(1:end) + Utilde = ttm(X, U, -n, 't'); + + % Maximize norm(Utilde x_n W') wrt W and + % keeping orthonormality of W + U{n} = nvecs(Utilde,n,R(n)); + end + + % Assemble the current approximation + core = ttm(Utilde, U, n, 't'); + + % Compute fit + normresidual = sqrt( normX^2 - norm(core)^2 ); + fit = 1 - (normresidual / normX); %fraction explained by model + fitchange = abs(fitold - fit); + + if mod(iter,printitn)==0 + fprintf(' Iter %2d: fit = %e fitdelta = %7.1e\n', iter, fit, fitchange); + end + + % Check for convergence + if (iter > 1) && (fitchange < fitchangetol) + break; + end + +end + +T = ttensor(core, U); + +end + + diff --git a/fe/feBuildDictionaries.m b/fe/feBuildDictionaries.m new file mode 100755 index 0000000..0674d0e --- /dev/null +++ b/fe/feBuildDictionaries.m @@ -0,0 +1,57 @@ +function fe = feBuildDictionaries(fe,Nphi,Ntheta) +% - Ntheta: number of discretization steps in Theta (azimuth) +% - Nphi: number of discretization steps in Phi (pi/2 - elevetion) +% - orient: (3 x Norient) containing in its columns the unit +% vectors covering half of the 3D unit sphere. These are the orientations +% that will be used to compute the dictionary of kernels. +% Norient = (Nphi-2)(Ntheta-2) + 1. The first column in orient is a vector +% pointing out to the zenith (spin-up) the rest of columns are vectors +% covering the half sphere. + +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + +tic +fprintf(['\n[%s] Computing demeaned difussivities Dictionary in a (',num2str(Nphi),'x',num2str(Ntheta),')-grid', ' ...'],mfilename); +fprintf('took: %2.3fs.\n',toc) + +% Compute orientation vectors +Norient = (Ntheta-1)*Nphi + 1; +orient = zeros(3,Norient); +deltaTheta = pi/Ntheta; +deltaPhi = pi/Nphi; + +sinTheta = sin(deltaTheta:deltaTheta:pi-deltaTheta); +cosTheta = cos(deltaTheta:deltaTheta:pi-deltaTheta); +sinPhi = sin(0:deltaPhi:pi-deltaPhi); +cosPhi = cos(0:deltaPhi:pi-deltaPhi); + +orient(:,1) = [0;0;1]; + +orient(1,2:end) = kron(cosPhi,sinTheta); +orient(2,2:end) = kron(sinPhi,sinTheta); +orient(3,2:end) = repmat(cosTheta,[1,Nphi]); + +% Compute Dictionary of Demeaned Signals for Canonical Diffusivities +nBvecs = feGet(fe,'nBvecs'); +bvecs = feGet(fe,'bvecs'); % bvecs +bvals = feGet(fe,'bvals'); % bvals + +DictSig = zeros(nBvecs,Norient); % Initialize Signal Dictionary matrix +%DictTensors = zeros(9,Norient); % Initialize Tensors Dictionary matrix + +D = diag(fe.life.modelTensor); % diagonal matix with diffusivities + +% Compute each dictionary column for a different kernel orientation +for j=1:Norient + [Rot,~, ~] = svd(orient(:,j)); % Compute the eigen vectors of the kernel orientation + + Q = Rot*D*Rot'; + %DictTensors(:,j) = Q(:); + DictSig(:,j) = exp(- bvals .* diag(bvecs*Q*bvecs')); % Compute the signal contribution of a fiber in the kernel orientation divided S0 + DictSig(:,j) = DictSig(:,j) - mean(DictSig(:,j)); % demeaned signal +end + +fe = feSet(fe,'dictionary parameters',{Nphi,Ntheta,orient,DictSig}); + +end \ No newline at end of file diff --git a/fe/feConnectomeBuildModel.m b/fe/feConnectomeBuildModel.m new file mode 100755 index 0000000..9d7b52e --- /dev/null +++ b/fe/feConnectomeBuildModel.m @@ -0,0 +1,210 @@ +function fe = feConnectomeBuildModel(fe,Compute_matrix_M) +% Compute multiway decompositon model to predict directional diffusion in each voxel from fibers +% +% fe = feConnectomeBuildModel(fe) +% +% INPUTS: fe - An fe structure, see feCreate.m +% +% See also: feFitModel.m, feComputePredictedSignal.m +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com +% + +if notDefined('fe'), error('LiFE (fe = feCreate) struct needed'); end +if ~isfield(fe,'life') + error('LiFE - the field ''life'' is necessary in the fe structure.') +end + +fprintf('\n[%s] Building the Connetome Model (Indication Tensor Phi) ... ',mfilename); +tic + + +nFibers = feGet(fe,'n fibers'); +nTotalNodes = fefgGet(fe.fg,'n total nodes'); +fibers = fe.fg.fibers; +imgsize = feGet(fe,'volumesize'); +imgsize = imgsize(1:3); % 4th dimension is discarded +nTotalVoxels = prod(imgsize); % including voxels not in the ROI + +nAtoms = feGet(fe,'n Atoms'); +%orient = feGet(fe,'orient'); +Nphi = feGet(fe,'Nphi'); +Ntheta = feGet(fe,'Ntheta'); + +% Compute fiber +[tubes,grad] = fiberOfNodes(fibers,nTotalNodes); % this function gives a (1xnTotalNodes) containing the fiber number for each node +fibers = cell2mat(fibers(:)'); + +% Compute voxels +voxel_coord = ceil(fibers) + 1; +cols = sub2ind(imgsize, voxel_coord(1,:)', voxel_coord(2,:)', voxel_coord(3,:)'); + +% Compute atoms +%grad = gradient(fibers); +grad = grad./repmat(sqrt(sum(grad.^2)),3,1); % normalize columns + +rows = get_atom(grad,Nphi,Ntheta); + +% Construct Indication Tensor Phi +Phi = sptensor([rows,cols,tubes],ones(nTotalNodes,1),[nAtoms,nTotalVoxels,nFibers]); + +% The following sparse matrix (Nvoxels x Nfibers) counts the number of +% nodes per fiber per voxel. +A = sparse(cols,tubes,ones(nTotalNodes,1),nTotalVoxels,nFibers); + +roi_coords = feGet(fe,'roicoords'); +roi_ind = sub2ind(imgsize,roi_coords(:,1)',roi_coords(:,2)',roi_coords(:,3)'); + +Phi = Phi(:,roi_ind,:); % reduce tensor in 3rd dimension to roi voxels only +A = A(roi_ind,:); + +vox = Phi.subs(:,2); +fib = Phi.subs(:,3); +vals = Phi.vals; + +nVoxels = length(roi_ind); +a = A(:); +vals = vals./a(sub2ind([nVoxels,nFibers],vox,fib)); + +Phi = sptensor(Phi.subs,vals,size(Phi)); + +% The following multiplies every slice by the corresponding S0(voxel) value +S0 = feGet(fe,'s0_img'); +vals = Phi.vals.*S0(Phi.subs(:,2)); +Phi = sptensor(Phi.subs,vals,size(Phi)); + +fe = feSet(fe,'Indication Tensor',Phi); + + +if Compute_matrix_M % This was introduced in order to compare OLD vs NEW LiFE + % Compute Large sparse matrix M (as in the old LiFE) + disp('Computing large and sparse matrix M (as in the old LiFE)') + + nBvecs = feGet(fe,'nBvecs'); + bvecs = feGet(fe,'bvecs'); % bvecs + bvals = feGet(fe,'bvals'); % bvals + nodeSig = zeros(nBvecs,nTotalNodes); + + D = diag(fe.life.modelTensor); % diagonal matix with diffusivities + parfor j=1:nTotalNodes + disp(['Computing diffusion of node ',num2str(j),'/',num2str(nTotalNodes)]); + [Rot,~, ~] = svd(grad(:,j)); % Compute the eigen vectors of the kernel orientation + Q = Rot*D*Rot'; + nodeSig(:,j) = exp(- bvals .* diag(bvecs*Q*bvecs')); % Compute the signal contribution of a fiber in the kernel orientation divided S0 + nodeSig(:,j) = nodeSig(:,j) - mean(nodeSig(:,j)); % demeaned signal + end + + indi = zeros(nBvecs*nTotalNodes,1); + indj = zeros(nBvecs*nTotalNodes,1); + vals = zeros(nBvecs*nTotalNodes,1); + + % Construction of nonzero indices of matrix M + for node=1:nTotalNodes + disp(['Building matrix M, node ',num2str(node),'/',num2str(nTotalNodes)]); + indi((node-1)*nBvecs + 1 : node*nBvecs) = [(cols(node)-1)*nBvecs+1:cols(node)*nBvecs]'; + indj((node-1)*nBvecs + 1 : node*nBvecs) = repmat(tubes(node),[nBvecs,1]); + vals((node-1)*nBvecs + 1 : node*nBvecs) = nodeSig(:,node); + end + + % June 27/6/2015 + clear nodeSig Phi rows cols tubes fibers grad voxel_coord + + Mmatrix = sparse(indi, indj, vals); + kept_ind = zeros(length(roi_ind)*nBvecs,1); + for i=1:length(roi_ind) + disp(['Keeping voxels that are in ROI, voxel= ',num2str(i),'/',num2str(length(roi_ind))]); + kept_ind((i-1)*nBvecs+1:i*nBvecs) = (roi_ind(i)-1)*nBvecs + 1: roi_ind(i)*nBvecs; + end + + Mmatrix = Mmatrix(kept_ind,:); % reduce Matrix + [indi,indj,vals]=find(Mmatrix); + + vox = ceil(indi/nBvecs); + vals = vals.*S0(vox); + Mmatrix = sparse(indi,indj,vals); + + + fe.life.M.Mmatrix = Mmatrix; +end + +fprintf('took: %2.3fs.\n',toc) + +return +end + + +function [tubes, grad] = fiberOfNodes(fibers,nTotalNodes) + tubes = zeros(nTotalNodes,1); + grad = zeros(3,nTotalNodes); + node = 1; + for f = 1:size(fibers,1) + NumberOfNodes = size(fibers{f},2); + tubes(node:node+NumberOfNodes-1) = f; + grad(:,node:node+NumberOfNodes-1) = gradient(fibers{f}); + node = node + NumberOfNodes; + end +end + + +function atom_ind = get_atom(vect,Nphi,Ntheta) + deltaTheta = pi/Ntheta; + deltaPhi = pi/Nphi; + + % vector should belong to the positive half of the sphere + vect(:,vect(2,:)<0) = -vect(:,vect(2,:)<0); + + [angPhi,angTheta,r] = cart2sph(vect(1,:)',vect(2,:)',vect(3,:)'); + angTheta = pi/2 - angTheta; % we measure theta as the angle with the positive semi-axis y + % ind_Phi=1 correspond to Phi=0, ind_Phi=Nphi to Phi = Pi - delta_Phi + ind_Phi = round(angPhi/deltaPhi) + 1; + + % ind_Phi=1 correspond to Phi=0, ind_Phi=Nphi to Phi = Pi - delta_Phi + indsub = find(ind_Phi == Nphi+1); + ind_Phi(indsub) = 1; + angTheta(indsub) = pi - angTheta(indsub); + + % ind_Theta=1 correspond to Theta=delta_Theta, ind_Theta=NTheta-1 to + % Phi = Pi - delta_Theta + ind_Theta = round(angTheta/deltaTheta); + + indsub = find((ind_Theta ~= 0) & (ind_Theta ~= Ntheta)); + atom_ind = ones(size(ind_Phi)); + atom_ind(indsub) = sub2ind([Ntheta-1,Nphi],ind_Theta(indsub),ind_Phi(indsub)) + 1; + + +end + + +% This function computes the atom indexing in a (Nphi x Ntheta)-grid dictionary corresponding to a given +% orientation vect +% function atom_ind = get_atom(vect,Nphi,Ntheta) +% deltaTheta = pi/Ntheta; +% deltaPhi = pi/Nphi; +% +% % vector should belong to the positive half of the sphere +% if vect(2) < 0 +% vect = - vect; +% end +% +% % cartesian to spherical coordinates +% [angPhi,angTheta,r] = cart2sph(vect(1),vect(2),vect(3)); +% angTheta = pi/2 - angTheta; % we measure theta as the angle with the positive semi-axis y +% +% % ind_Phi=1 correspond to Phi=0, ind_Phi=Nphi to Phi = Pi - delta_Phi +% ind_Phi = round(angPhi/deltaPhi) + 1; +% if ind_Phi == Nphi+1 +% ind_Phi = 1; +% angTheta = pi - angTheta; +% end +% +% % ind_Theta=1 correspond to Theta=delta_Theta, ind_Theta=NTheta-1 to +% % Phi = Pi - delta_Theta +% ind_Theta = round(angTheta/deltaTheta); +% +% if (ind_Theta == 0) || (ind_Theta == Ntheta) +% atom_ind = 1; % spin-Up or spin-Down case +% else +% atom_ind = sub2ind([Ntheta-1,Nphi],ind_Theta,ind_Phi) + 1; +% end +% end diff --git a/fe/feConnectomeInit.m b/fe/feConnectomeInit.m new file mode 100755 index 0000000..5e07746 --- /dev/null +++ b/fe/feConnectomeInit.m @@ -0,0 +1,130 @@ +function fe = feConnectomeInit(dwiFile,fgFileName,feFileName,savedir,dwiFileRepeated,anatomyFile,varargin) +% Initialize a new connectome (fe) structure. +% +% fe = feConnectomeInit(dwiFile,dtFile,fgFileName,feFileName,savedir,dwiFileRepeated,anatomyFile,varargin); +% +% We allow a set of (paramName,val) pairs in the varargin that will be +% executed as fe = feSet(fe,paramName,val) +% +% Example: +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + +%feOpenLocalCluster + +% Intialize the fe structure. +fe = feCreate; + +% Set the based dir for fe, this dire will be used +if notDefined('savedir'), savedir = fullfile(fileparts(fgFileName),'life'); +end +fe = feSet(fe,'savedir',savedir); + +% Set the xforms (transformations from diffusion data to acpc) +tempNi = niftiRead(dwiFile); +fe = feSet(fe, 'img2acpc xform', tempNi.qto_xyz); +fe = feSet(fe, 'acpc2img xform', inv(tempNi.qto_xyz)); +clear tempNi + +% Set up the fe name +if isstruct(fgFileName), n = fgFileName.name; +else [~,n] = fileparts(fgFileName); +end + +if notDefined('feFileName'), + feFileName = sprintf('%s-%s', datestr(now,30),n); +end +fe = feSet(fe, 'name',feFileName); + +% Load a connectome +if isstruct(fgFileName), fg = fgFileName; clear fgFileName +else % A file name was passed load the fibers from disk + fprintf('\n[%s]\n loading fiber from file: %s\n',mfilename,fgFileName) + fg = fgRead(fgFileName); +end + +% Set fg in the fe structure identifying the fg coordinate frame. +% Everything in LiFE is in img coordinates, but everyting in mrDiffusion is in acpc. +% So here we assume the fibers are read in acpc and we xform them in img. +fe = feSet(fe,'fg from acpc',fg); + +% Precompute the canonical tensors for each node in each fiber (NOT NEEDED ANYMORE). + +% Set model for canonical tensor +%tic +if ~isempty(varargin) + N = varargin{1}(1); + axialDiffusion = varargin{2}(1); + radialDiffusion = varargin{2}(2); + Compute_matrix_M = varargin{3}; +else % Default to stick and ball + N = 360; + axialDiffusion = 1; + radialDiffusion = 0; + Compute_matrix_M = 0; +end +dParms(1) = axialDiffusion; +dParms(2) = radialDiffusion; +dParms(3) = radialDiffusion; +Nphi = N; +Ntheta = N; + +fe = feSet(fe,'model tensor',dParms); + +% NOT NEEDED ANYMORE +%fprintf('\n[%s] Computing fibers'' tensors... ',mfilename); +%fe = feSet(fe, 'tensors', feComputeCanonicalDiffusion(fe.fg.fibers, dParms)); +%toc + +%% This should be changed (computation of ROI) +fe = feSet(fe,'roi fg',[]); +clear fg + +%% The following is not needed anymore +% When the ROI is set to empty, LiFE uses all of the voxels within the +% connectome as the ROI. + +% % NEW: Compuet direction of fibers (gradient) and Maxelem (Maximum number of nodes per fiber) +% tic +% fprintf('\n[%s] Computing fiber directions (gradient) ...',mfilename); +% fe = feSet(fe, 'gradients', feComputeGradients(fe.fg.fibers)); +% fprintf('took: %2.3fs.\n',toc) +% +% % We disregard fibers that have identical trajectories within the ROI. +% roi = feGet(fe,'roi coords'); +% fe = feSet(fe,'voxel 2 fiber node pairs',fefgGet(feGet(fe,'fg img'),'v2fn',roi)); +% clear roi; +% +% % This compute the unique fibers per voxels +% fe = feGetConnectomeInfo(fe); + + +% Install the information about the diffusion data. +fe = feConnectomeSetDwi(fe,dwiFile,0); + +% Install the information about a repeated measurement of the diffusion +% data. +if ~notDefined('dwiFileRepeated') + fe = feConnectomeSetDwi(fe,dwiFileRepeated,1); +end + +% Install the path tot he anatomical high-resolution file. +if ~notDefined('anatomyFile') + fe = feSet(fe,'anatomy file',anatomyFile); +end + +%% NEW: Precompute Dictionary of orientations and canonical demeaned signals +% Define discretization steps for building Dictionary of canonical difussivities +% These numbers represents the steps in which the range [0,pi] is divided +% for spherical coordinates phi: azimuth and theta: pi/2-elevetion + +fe = feBuildDictionaries(fe,Nphi,Ntheta); + +%% NEW: The previous very large matrix M was replaced by a sparse multiway decomposition +% Build LiFE tensors and key connection matrices +fe = feConnectomeBuildModel(fe,Compute_matrix_M); + +fprintf(['\n[%s] fe-structure Memory Storage:',ByteSize(fe),'\n'],mfilename); + +return diff --git a/fe/feConnectomeSetDwi.m b/fe/feConnectomeSetDwi.m new file mode 100755 index 0000000..94931dd --- /dev/null +++ b/fe/feConnectomeSetDwi.m @@ -0,0 +1,60 @@ +function fe = feConnectomeSetDwi(fe,dwiFileName,isrepeat) +% Set all the fields necessary to store the DWI measurements. +% +% This can be used for the dwi measurements use to build the model as well +% as for those used as a second repeat. +% +% Inputs: +% fe - an fe structure +% dwiFileName - the full path to a dwi nifti file +% isrepeat - wether the file being set up is the origianl data used to +% build LiFE or a repeated measurements used to compute +% statistcs of the quality of fit. +% Outputs: +% fe - fe structure with data added in the appropriate fields. +% +% fe = feConnectomeSetDwi(fe,dwiFileName); % Set the original data +% fe = feConnectomeSetDwi(fe,dwiFileName,1); % Set the repeated measure +% % data +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + +% Check inputs +if notDefined('isrepeat'), isrepeat=0;end + +% Build a tag for the calls to feSet. +if isrepeat, tag = sprintf('repeat'); +else tag = sprintf(''); +end + +% Set the ile name in the structure +fe = feSet(fe, sprintf('dwi%sfile',tag),dwiFileName); + +% load the dwi data +dwi = feGet(fe, sprintf('dwi%s',tag)); + +% Store the bvecs, bvals and the indices for the new file. +fe = feSet(fe, sprintf('diffusion bvecs %s',tag), ... + dwiGet(dwi, 'diffusion bvecs')); +fe = feSet(fe, sprintf('diffusion bvals %s',tag), ... + dwiGet(dwi, 'diffusion bvals')); +fe = feSet(fe, sprintf('bvecs indices %s',tag), ... + dwiGet(dwi, 'diffusionimagenums')); + +% Extract the dwi signal at the coordinates of the connectome +fe = feSet(fe, sprintf('diffusion signal image %s',tag), ... + dwiGet(dwi, 'diffusion signal image',feGet(fe,'roi coords')) ); + +% Extract the non-diffusion direction signal at the coordinates of the +% conenctome +fe = feSet(fe, sprintf('S0 image %s',tag), ... + dwiGet(dwi, 'S0 image',feGet(fe,'roi coords'))); + +if length(isrepeat)>1, keyboard;end + +% Here I set the dimensions of the dwi file so that I have that +% available everytime when creating a map of parameters. +fe = feSet(fe,sprintf('img size %s',tag),dwiGet(dwi,'size')); + +end diff --git a/fe/feCreate.m b/fe/feCreate.m new file mode 100755 index 0000000..53a4864 --- /dev/null +++ b/fe/feCreate.m @@ -0,0 +1,53 @@ +function fe = feCreate +% Create a linear fascicle evaluation structure +% +% fe = feCreate +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + +% Book-keeping +fe.name = 'default'; % This one's name +fe.type = 'faseval'; % Always fascicle evaluation + +% Overview +fe.life = []; % Structure of parameters and results from LIFE analysis +fe.fg = []; % Fiber group candidate fascicles, uses fgSet/Get +fe.roi = []; % Cell array of regions of interest where we evaluate + +% Path to files +fe.path.dwifile = []; % Diffusion weighted file used for testing results +fe.path.dtfile = []; % Diffusion weighted file used for testing results +fe.path.savedir = []; % Top directory under which all files will be saved +fe.path.anatomy = []; % 3D high-resolution anatomical file +fe.path.dwifilerep = []; % File used for cross-validating the results. + % A secodn measuremnt ideally acquried in the + % same session witht the same scanning + % parameters. + +% Life Algorithm parameters +%fe.life.Mfiber = []; % Fiber portion of A matrix +%fe.life.voxel2FNpair = []; % Voxels to fiber/node pair, fefgGet(fg,'voxel 2 fiber node pair') +%fe.life.M.orient = []; % Dictionary of orientations +%fe.life.M.DictSig = []; % Dictionary of Demeaned Signals +fe.life.M.Phi = []; % Indication Tensor: sparse-(nFibers x nAtoms x nVoxels) 3way array +%fe.life.dSig = []; % Signal of fibers alone (demeaned). +%fe.life.Mfiber = []; +%fe.life.voxel2FNpair = {}; +%fe.life.dSig = []; +fe.life.xform = []; +fe.life.fibers = []; +fe.life.diffusion_signal_img = []; +fe.life.diffusion_S0_img = []; +fe.life.bvecs = []; +fe.life.bvals = []; +fe.life.bvecsindices = []; +fe.life.imagedim = []; +fe.life.xform = []; % Transforms between coords for fg, roi, and dwi data +fe.life.xform.img2acpc = []; +fe.life.xform.acpc2img = []; + +% Repetition file for cross-validation +fe.rep = []; + +return diff --git a/fe/feGet.m b/fe/feGet.m new file mode 100755 index 0000000..3c0f6f8 --- /dev/null +++ b/fe/feGet.m @@ -0,0 +1,1627 @@ +function val = feGet(fe,param,varargin) +% Get function for fascicle evaluation structure +% +% val = feGet(fe,param,varargin) +% +% +% INPUTS: +% Coords - Nx3 set of coordinates in image space +% voxelIndices - Vector of 1's and 0's, there is a one for each +% location the the connectome coordinates for which there is +% a match in the coords +% +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com +% +% +%---------- List of arguments ---- +% Name of the current fe structure. +% name = feGet(fe,'name') +%---------- +% The type of objes (always, fascicle evaluation) +% type = feGet(fe,'type') +%---------- +% Structure of parameters and results from LIFE analysis +% life = feGet(fe,'life') +%---------- +% Return the connectome (fiber group) in image coordinates. +% fg = feGEt(fe,'fg img') +%---------- +% return the connectome in acpc coordinates. +% fg = feGet(fg,'fg acpc') +%---------- +% Return the VOI comprised by the full connectome. +% roi = feGet(fe,'roi') +%---------- +% Transforms between coords for fg, roi, and dwi data +% xform = feGet(fe,'xform') +%---------- +% Load the diffusion weighted data. +% dwi = feGet(fe,'dwi') +%---------- +% Return the path to the diffusion weighted data file. +% dwiFile = feGet(fe,'dwifile') +%---------- +% Load the repeated-measure diffusion weighted data. +% dwi = feGet(fe,'dwirepeat') +%---------- +% Load the repeated measure of the diffusion weighted data. +% dwiFile = feGet(fe,'dwirepeatfile') +%---------- +% Directory where the LiFe structes are saved by defualt. +% sdir = feGet(fe,'savedir'); +%---------- +% Diffusion directions. +% val = feGet(fe,'bvecs'); +%---------- +% Indices to the diffusion directions in the DWi 4th Dimension. +% val = feGet(fe,'bvecs indices'); +%---------- +% Number of B0's +% val = feGet(fe,'n bvals'); +%---------- +% B0 Values. +% bval = feGet(fe,'bvals') +%---------- +% Returns a nVoxels X nBvecs array of measured diffusion signal +% val = feGet(fe,'dsiinvox'); +% val = feGet(fe,'dsiinvox',voxelsIndices); +% val = feGet(fe,'dsiinvox',coords); +%---------- +% Returns a nVoxels X nBvecs array of demeaned diffusion signal +% val =feGet(fe,'dsiinvoxdemeaned'); +% val =feGet(fe,'dsiinvoxdemeaned',voxelsIndices); +% val =feGet(fe,'dsiinvoxdemeaned',coords); +%---------- +% Get the diffusion signal at 0 diffusion weighting (B0) for this voxel +% val = feGet(fe,'b0signalvoxel'); +% val = feGet(fe,'b0signalvoxel',voxelIndex); +% val = feGet(fe,'b0signalvoxel',coords); +%---------- +% Return a subset of fibers from the conenctome. +% fg = feGet(fe,'fiberssubset',fiberList); +%---------- +% Return the coordinates of the VOI comprised in the connectome. +% Always in image space. +% coords = feGet(fe,'roi coords') +%---------- +% Number of voxels in the connectome/VOI. +% nVoxels = feGet(fe,'n voxels') +%---------- +% Indexes of actually used voxels. +% These can be different than the number of voxels in the VOI in case some +% voxels have no fibers in them. +% +% TO BE DEPRECATED. +% indxUsedVx = feGet(fe,'index of used voxels') +%---------- +% Number of actually used voxels. +% This can be less than the number of voxels in the VOI in case some +% voxels have no fibers in them. +% +% TO BE DEPRECATED. +% nUsedVx = feGet(fe,'index of used voxels') +%---------- +% Returns the first index to a voxel in the dSig vector. +% The dSig vector is 1:nBvecs*nVoxels. +% val = feGet(fe,'start rows') +%---------- +% Return the rows corresponding to a set of voxels. +% rows = feGet(fe,'voxel rows',idxVoxel) +%---------- +% Return the model (M matrix), or a subset of it. +% Mfiber = feGet(fe,'M fiber'); +% Mfiber = feGet(fe,'model',voxelsIndices); +% Mfiber = feGet(fe,'model',coords); +%---------- +% Return a subset of measurements from the fiber portion of M matrix +% The rows of M are specified. Remember that the rows refer to a +% combination of voxel and measurement direction and potentially in the +% future a b-value. Hence, the rows are not specific to a voxel. +% Mfiber = feGet(fe,'mfiber subset',rowsToKeep); +%---------- +% Pairing of fibers and nodes in each voxel. +% v2fnp = feGet(fe,'v2fnp'); +%---------- +% Tensors computed for each node and fiber in a set of voxels. +% t = feGet(fe,'tensors') +% t = feGet(fe,'tensors',voxelsIndices); +% t = feGet(fe,'tensors',coords); +%---------- +% Get all the tensors in a single voxel. +% val = feGet(fe,'voxtensors',voxelIndex) +% val = feGet(fe,'voxtensors',coord) +%---------- +% Returns the model (M) with only a subset of columns (fibers). +% fiberList is a vector of indexes, e.g, [1 10 100] +% M = feGet(fe,'keepfibers',fiberList) +%---------- +% Isotropic portion of M matrix. Returns the matrix for the full model or +% for a subset of voxels. +% Miso = feGet(fe,'M iso') +% Miso = feGet(fe,'M iso',voxelsIndices) +% Miso = feGet(fe,'M iso',coords) +%---------- +% Total number of nodes in each voxel The voxel2FN pairs are row size +% equals number of nodes and column size is always 2. The entries of +% the first column are the fiber number. The entries in the second +% column are the node of the fiber inside the voxel. +% val = feGet(fe,'n nodes'); +% val = feGet(fe,'n nodes',voxelsIndices); +% val = feGet(fe,'n nodes',coords); +%---------- +% Return the total number of fibers for all the voxels or in a set of +% voxels. +% nFibers = feGet(fe,'uniquefnum'); % all the voxels +% nFibers = feGet(fe,'uniquefnum',[1 2 3 4]); % for some the voxels, +% % specified by indexes +% nFibers = feGet(fe,'uniquefnum',coords); % for some the voxels, +% % specified by coordinates +%---------- +% Return the indexes of the fibers for all the voxels or in a set of +% voxels. +% idxFibers = feGet(fe,'uniquef'); % all the voxels +% idxFibers = feGet(fe,'uniquef',[1 2 3 4]); % for some the voxels, +% % specified by indexes +% idxFibers = feGet(fe,'uniquef',coords); % for some the voxels, +% % specified by coordinates +%---------- +% Return the total number of fibers for all the voxels or in a set of +% voxels +% nFibers = feGet(fe,'totfnum'); % all the voxels +% nFibers = feGet(fe,'totfnum',[1 2 3 4]); % for some the voxels, +% % specified by indexes +% nFibers = feGet(fe,'totfnum',coords); % for some the voxels, +% % specified by coordinates +%---------- +% Return the indexes of the fibers for all the voxels or in a set of +% voxels +% idxFibers = feGet(fe,'totf'); % all the voxels +% idxFibers = feGet(fe,'totf',[1 2 3 4]); % for some the voxels, +% % specified by indexes +% idxFibers = feGet(fe,'totfibers',coords); % for some the voxels, +% % specified by coordinates +%---------- +% Return the number of fibers in the model. +% nFibers = feGet(fe,'n fibers'); +%---------- +% Weights of the isotropic voxel signals, this is the mean signal in +% each voxel. +% val = feGet(fe,'iso weights'); +% val = feGet(fe,'iso weights'coords) +% val = feGet(fe,'iso weights',voxelIndices) +%---------- +% Weights of the fiber component. For all the fibers or a subset of +% them. +% w = feGet(fe,'fiber weights') +% w = feGet(fe,'fiber weights',fiberIndices) +%---------- +% Weights of the fiber component with a subset of the fibers' weights +% set to zero. This can be used to test the loss in RMSE for the +% connectome when a subset of fibers is removed, but the connectome is +% not fitted again. +% w = feGet(fe,'fiber weights test',fiberIndices) +%---------- +% Predicted signal (demeaned) with a subset of fibers' weights set to 0. +% This can be used to test the loss in RMSE for the connectome when a +% subset of fibers is removed, but the connectome is not fitted again. +% +% pSig = feGet(fe,'pSig fiber test',fiberIndices); +% pSig = feGet(fe,'pSig fiber test',fiberIndices,voxelIndices); +% pSig = feGet(fe,'pSig fiber test',fiberIndices,coords); +%---------- +% Measured signal in VOI, this is the raw signal. not demeaned +% +% dSig = feGet(fe,'dSig full') +%--------- +% Measured signal in VOI, demeaned, this is the signal used for the +% fiber-portion of the M model. +% +% dSig = feGet(fe,'dsigdemeaned'); +% dSig = feGet(fe,'dsigdemeaned',[1 10 100]); +% dSig = feGet(fe,'dsigdemeaned',coords); +%--------- +% Get the demeaned signal for a subset of rows. +% Useful for cross-validation. +% dSig = feGet(fe,'dsigrowssubset',voxelsList); +%--------- +% Predicted signal of fiber alone (demeaned). +% pSig = feGet(fe,'pSig fiber'); +% pSig = feGet(fe,'pSig fiber',coords); +% pSig = feGet(fe,'pSig fiber',voxelIndices); +%--------- +% Predicted measured signal from both fiber and iso +% pSig = feGet(fe,'pSig full') +% pSig = feGet(fe,'pSig full',coords) +% pSig = feGet(fe,'pSig full',voxelIndices) +%--------- +% The woxels returned by a fit of LiFE by voxel/fiber +% w = feGet(fe,'fiberweightsvoxelwise') +%--------- +% Predict the diffusion signal for the fiber component +% with the voxel-wise fit of LiFE +% pSig = feGet(fe,'psigfvoxelwise') +% pSig = feGet(fe,'psigfvoxelwise',coords) +% pSig = feGet(fe,'psigfvoxelwise',voxelIndices) +%--------- +% Predict the diffusion signal for the fiber component +% with the voxel-wise fit of LiFE, return the an array of pSigXnVoxel +% pSig = feGet(fe,'psigfvoxelwisebyvoxel') +% pSig = feGet(fe,'psigfvoxelwisebyvoxel',coords) +% pSig = feGet(fe,'psigfvoxelwisebyvoxel',voxelIndices) +%--------- +% The fiber and isotropic weights as a long vector +% w = feGet(fe,'fullweights') +%--------- +% Return the global R2 (fraction of variance explained) of the full life +% model. +% R2 = feGet(fe,'total r2'); +%--------- +% Percent variance explained +% R2 = feGet(fe,'explained variance') +%--------- +% Root mean squared error of the LiFE fit to the whole data +% rmse = feGet(fe,'rmse') +%--------- +% Residual signal: (fiber prediction - measured_demeaned). +% res = feGet(fe,'res sig fiber') +%--------- +% Residual signal: (full model prediction - measured signal). +% res = feGet(fe,'res sig full'); +%--------- +% Residual signal: (fiber model prediction - demeaned measured signal) +% with added mean signal. Res is returned as a vector. +% This is used to reconstruct an image (volume) to be used for the +% refinement process. +% res = feGet(fe,'fiber res sig with mean'); +% res = feGet(fe,'fiber res sig with mean',coords); +% res = feGet(fe,'fiber res sig with mean',voxelIndices); +%--------- +% Residual signal fiber model prediction - demeaned measured signal +% with added mean signal. Res is returned as an array (nBvecs x nVoxel). +% This is used to reconstruct an image (volume) to be used for the +% refinement process. +% res = feGet(fe,'fiber res sig with mean voxel'); +% res = feGet(fe,'fiber res sig with mean voxel',coords); +% res = feGet(fe,'fiber res sig with mean voxel',voxelIndices); +%--------- +% Predicted signal by the fiber model in a set of voxels. +% Vox subfield stores per voxel within the VOI. The pSig has size of the +% dwi. - It is stored as val = pSig(X,Y,Z,Theta) +% +% pSig = feGet(fe, 'pSig fiber by voxel'); +% pSig = feGet(fe, 'pSig fiber by voxel',coords); +% pSig = feGet(fe, 'pSig fiber by voxel',voxelIndex); +%--------- +% Return a column vector of the proportion of variance explained in +% each voxel. +% R2byVox = feGet(fe,'voxr2'); +% R2byVox = feGet(fe,'voxr2',coords); +%--------- +% Return a column vector of the proportion of variance explained in +% each voxel. (Normalized to the squared mean diffusion signal in each voxel) +% R2byVox = feGet(fe,'voxr2zero'); +% R2byVox = feGet(fe,'voxr2zero',coords); +%--------- +% Return the percent of varince explained in each voxel. +% R2byVox = feGet(fe,'var exp by voxel'); +% R2byVox = feGet(fe,'var exp by voxel',coords); +%--------- +% Demeaned diffusion signal in each voxel. +% dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel'); +% dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel',coords); +% dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel',vxIndex); +%--------- +% Full (measured) signal in each voxel. +% dSigByVoxel = feGet(fe,'dSig full by Voxel'); +% dSigByVoxel = feGet(fe,'dSig full by Voxel',coords); +% dSigByVoxel = feGet(fe,'dSig full by Voxel',vxIndex); +%--------- +% Predicted signal by the full model in a set of voxeles. +% pSigByVoxel = feGet(fe, 'pSig full by voxel'); +% pSigByVoxel = feGet(fe, 'pSig full by voxel',coords); +% pSigByVoxel = feGet(fe, 'pSig full by voxel',voxelIndex); +%--------- +% A volume of RMSE values. +% RMSE = feGet(fe,'vox rmse') +% RMSE = feGet(fe,'vox rmse',coords) +% RMSE = feGet(fe,'vox rmse',vxIndex) +%--------- +% A volume of RMSE values with a subset of fibers' weights set to 0. +% RMSE = feGet(fe,'vox rmse',fiberIndices) +% RMSE = feGet(fe,'vox rmse',fiberIndices,coords) +% RMSE = feGet(fe,'vox rmse',fiberIndices,voxelIndex) +%--------- +% Fibers' residual signal by voxel. +% res = feGet(fe,'res sig fiber vox') +% res = feGet(fe,'res sig fiber vox',coords) +% res = feGet(fe,'res sig fiber vox',vxIndex) +%--------- +% Full (measured) residual signal by voxel. +% res = feGet(fe,'res sig full vox') +% res = feGet(fe,'res sig full vox',coords) +% res = feGet(fe,'res sig full vox',vxIndex) +%--------- +% Fibers' residual signal by voxel with mean signal added (with added +% isotropic component). +% This is used to compute the residual signal for the refinement. +% res = feGet(fe,'fiber res sig with mean vox') +% res = feGet(fe,'fiber res sig with mean vox',coords) +% res = feGet(fe,'fiber res sig with mean vox',vxIndex) +%--------- +% Residual signal full model prediction from a multi-voxel fit. +% res = feGet(fe,'res sig full voxfit'); +% res = feGet(fe, 'res sig full voxfit',coords); +% res = feGet(fe, 'res sig full voxfit',voxelIndex); +%--------- +% Fiber density statistics. +% Computes the fiber density (how many fibers in each voxel) +% We compute the following values: +% (1) The number of fibers in each voxel +% (2) The number of unique fibers with non-zero weights +% (3) The sum of the weights in each voxel +% (4) The mean of the weights in each voxel +% (5) The variance of the weigths in each voxel +% pSig = feGet(fe,'fiberdensity'); +%--------- +% Given an VOI or a set of indices to voxels returns the indices of the matching voxels inside the big +% volume, which ordinarily represents the full connectome. +% voxelIndices = feGet(fe,'voxelsindices',coords) +% IMPORTANT: Size(coords) must be Nx3; +% voxelIndices = feGet(fe,'voxelsindices',voxelIndices) +% IMPORTANT: Indices MUST be a column vector for this +% code to work. Size(voxelIndices) = Nx1; +%--------- +% Given an VOI finds the indices of the matching voxels inside the big +% volume, which ordinarily represents the full connectome. +% +% foundVoxels = feGet(fe,'find voxels',coords) +% +% coords is a Nx3 set of coordinates in image space +% foundVoxels is a vector of 1's and 0's, there is a one for each +% location the the connectome coordinates for which there is a match in +% the coords +%--------- +% Given a set of VOI coords finds the row numbers of the Model matrix +% (or equivalently the dSig vector) that represent the data for this +% set of VOI coords. +% foundVoxels = feGet(fe,'coords 2 rows',coords) +% coords - a Nx3 set of coordinates in image space +% foundVoxels - a binary vector that is 1 for each Model matrix row +% that corresponds to at least one of the coords. +%--------- +% Quaternian transformation from IMAGE space to ACPC space. +% xform = feGet(fe,'xform') +%--------- +% Quaternian transformation from ACPC space to IMAGE space. +% xform = feGet(fe,'xform') +%--------- +% Dimensions of the DW volume. +% dim = feGet(fe,'dims') +%--------- +% Dimensions of the maps of parameters and results. +% dims = feGet(fe, 'mapsize') +%--------- +% Path to the 3D Anatomy Volume. +% anatomyfile = feGet(fe, 't1 file') +% +% End of feGet.m parameters, +% +% Copyright (2013-2014), Franco Pestilli, Stanford University, pestillifranco@gmail.com. + +val = []; + +% Format the input parameters. +param = lower(strrep(param,' ','')); + +% Start sorting the input and computing the output. +switch param + case 'name' + % Name of the current fe structure. + % + % name = feGet(fe,'name') + val = fe.name; + + case 'type' + % The type of objes (always, fascicle evaluation) + % + % type = feGet(fe,'type') + val = fe.type; % Always fascicle evaluation + + % Set top level structure, not just single slot + case 'life' + % Structure of parameters and results from LIFE analysis + % + % life = feGet(fe,'life') + val = fe.life; + + case {'fgimg','fibersimg'} + % Return the connectome (fiber group) in image coordinates. + % + % fg = feGet(fe,'fg img') + val = fe.fg; % Fiber group candidate fascicles, uses fgSet/Get + + case {'fgacpc','fibersacpc'} + % return the connectome in acpc coordinates. + % + % fg = feGet(fg,'fg acpc') + xform = feGet(fe,'img2acpcxform'); + val = dtiXformFiberCoords(feGet(fe,'fgimg'),xform,'acpc'); + + case 'roi' + % Return the VOI comprised by the full connectome. + % + % roi = feGet(fe,'roi') + val = fe.roi; + + case 'roiacpc' + % Return the VOI comprised by the full connectome. + % + % roi = feGet(fe,'roi acpc') + name = sprintf('roi_%s',fe.fg.name); + randColor = rand(1,3); + val = dtiNewRoi(name,randColor,fefgGet(feGet(fe,'fg acpc'),'unique image coords')); + + case 'xform' + % Transforms between coords for fg, roi, and dwi data + % + % xform = feGet(fe,'xform') + val = fe.life.xform; + + case 'dwi' + % Load the diffusion weighted data. + % + % dwi = feGet(fe,'dwi') + val = dwiLoad(feGet(fe,'dwifile')); + + case 'dwirepeat' + % Load the diffusion weighted data. + % + % dwi = feGet(fe,'dwirepeat') + val = dwiLoad(feGetRep(fe,'dwifile')); + + case 'dwifile' + % Load the diffusion weighted data. + % + % dwiFile = feGet(fe,'dwifile') + val = fe.path.dwifile; + + case 'dwifilerep' + % Load the diffusion weighted data. + % + % dwiFile = feGet(fe,'dwifilerep') + val = fe.path.dwifilerep; + + case 'savedir' + % Directory where the LiFe structes are saved by defualt. + % + % sdir = feGet(fe,'savedir'); + val = fe.path.savedir; + + case {'bvecs'} + % Diffusion directions. + % + % val = feGet(fe,'bvecs'); + val = fe.life.bvecs; + + case {'bvecsindices'} + % Indices to the diffusion directions in the DWi 4th Dimension. + % + % val = feGet(fe,'bvecs indices'); + val = fe.life.bvecsindices; + + case {'nbvecs','nbvals'} + % Number of B0's + % + % val = feGet(fe,'n bvals'); + val = length(feGet(fe,'bvals')); + + case {'bvals'} + % B0 Values. + % + % bval = feGet(fe,'bvals') + val = fe.life.bvals; + + case {'diffusionsignalinvoxel','dsiinvox','dsigvox','dsigmeasuredvoxel'} + % Returns a nVoxels X nBvecs array of measured diffusion signal + % + % val = feGet(fe,'dsiinvox'); + % val = feGet(fe,'dsiinvox',voxelsIndices); + % val = feGet(fe,'dsiinvox',coords); + val = fe.life.diffusion_signal_img(feGet(fe,'voxelsindices',varargin),:)'; + + case {'diffusionsignalinvoxeldemeaned','dsiinvoxdemeaned'} + % Returns a nVoxels X nBvecs array of demeaned diffusion signal + % + % val =feGet(fe,'dsiinvoxdemeaned'); + % val =feGet(fe,'dsiinvoxdemeaned',voxelsIndices); + % val =feGet(fe,'dsiinvoxdemeaned',coords); + nBvecs = feGet(fe,'nBvecs'); + voxelIndices = feGet(fe,'voxelsindices',varargin); + val = fe.life.diffusion_signal_img(voxelIndices,:) - repmat(mean(fe.life.diffusion_signal_img(voxelIndices,:), 2),1,nBvecs); + keyboard + % THis seems to be wrong + + case {'b0signalimage','b0vox'} + % Get the diffusion signal at 0 diffusion weighting (B0) for this voxel + % + % val = feGet(fe,'b0signalvoxel'); + % val = feGet(fe,'b0signalvoxel',voxelIndex); + % val = feGet(fe,'b0signalvoxel',coords); + val = fe.life.diffusion_S0_img(feGet(fe,'voxelsindices',varargin), :); + + case {'fiberssubset','fsub','subsetoffibers','fgsubset'} + % Return a subset of fibers from the conenctome. + % + % fg = feGet(fe,'fiberssubset',fiberList); + val = feGet(fe,'fg img'); + fiberList = varargin{1}; + fibers = cell(size(fiberList)); + for ff = 1:length(fiberList) + fibers{ff} = val.fibers{fiberList(ff)}; + if isfield(val,'pathwayInfo') + pathInfo(ff) = val.pathwayInfo(fiberList(ff)); + end + end + val.fibers = fibers; + if isfield(val,'pathwayInfo') + val.pathwayInfo = pathInfo; + end + val.name = sprintf('subsetFrom:%s',val.name); + + case {'roivoxels','roicoords'} + % Return the coordinates of the VOI comprised in the connectome. + % Always in image space. + % + % coords = feGet(fe,'roi coords') + val = fe.roi.coords; + + case {'roicoordssubset'} + % Return the coordinates of the VOI comprised in the connectome. + % Always in image space. + % + % coords = feGet(fe,'roi coords') + val = feGet(fe,'roi coords'); + val = val(varargin{1},:); + + case {'nroivoxels','nvoxels'} + % Number of voxels in the connectome/VOI. + % + % nVoxels = feGet(fe,'n voxels') + val = size(feGet(fe,'roivoxels'),1); + + case {'usedvoxels','indexesofusedvoxels'} + % Indexes of actually used voxels. + % + % These can be different than the number of voxels in the VOI in case some + % voxels have no fibers in them. + % + % TO BE DEPRECATED. + % + % indxUsedVx = feGet(fe,'index of used voxels') + val = find(feGet(fe,'nnodes')); + + case {'nusedvoxels','numberofusedvoxels'} + % Number of actually used voxels. + % + % This can be less than the number of voxels in the VOI in case some + % voxels have no fibers in them. + % + % TO BE DEPRECATED. + % + % nUsedVx = feGet(fe,'index of used voxels') + val = size(feGet(fe,'used voxels'),2); + + case {'startrow','first index into the dsig vector for a voxel'} + % Returns the first index to a voxel in the dSig vector. + % + % The dSig vector is 1:nBvecs*nVoxels. + % + % val = feGet(fe,'start rows') + val = (varargin{1}-1)*feGet(fe,'nBvecs') + 1; + + case {'voxelrows','all indexes into the dsig vector for a set of voxels'} + % Return the rows corresponding to a set of voxels. + % + % rows = feGet(fe,'voxel rows',idxVoxel) + n = feGet(fe,'n voxels'); + nBvecs = feGet(fe,'n bvecs'); + voxelsToKeep = zeros(n,1); voxelsToKeep(varargin{1}) = 1; + val = logical(kron(voxelsToKeep(:),ones(nBvecs,1))); + + case {'modeltensor'} + val = fe.life.modelTensor; + + case {'mfiber','m','model'} + % Return the model (M matrix), or a subset of it. + % + % Mfiber = feGet(fe,'M fiber'); + % Mfiber = feGet(fe,'model',voxelsIndices); + % Mfiber = feGet(fe,'model',coords); + + % idxVoxels is an integer list of the voxels to retain + % If idxVoxels is not included, return the whole matrix + % M contains only the rows for the specified voxels (all directions) + + val = fe.life.M; + +% if isempty(varargin) +% % Return the whole M matrix +% val = fe.life.Mfiber; +% else +% % Return only the rows for the specified voxels, including all +% % directions. +% % voxelIndices = feGet(fe,'voxelsindices',varargin); +% % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); +% % val = fe.life.Mfiber(voxelRowsToKeep,:); +% val = fe.life.Mfiber(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin)),:); +% end + +% case {'mfibervoxelsubset','indexedafiber','mfiberindexed'} +% % Return a subset of measurements from the fiber portion of M matrix +% % The rows of M are specified. Remember that the rows refer to a +% % combination of voxel and measurement direction and potentially in the +% % future a b-value. Hence, the rows are not specific to a voxel. +% % +% % Mfiber = feGet(fe,'mfiber subset',rowsToKeep); +% +% if isempty(varargin), error('Subset of rows must be specified'); end +% val = fe.life.Mfiber(varargin{1},:); +% +% case {'msubsetfibers','mfiberssubset','mkeepfibers'} +% % Returns the model (M) with only a subset of columns (fibers). +% % +% % fiberList is a vector of indexes, e.g, [1 10 100] +% % +% % M = feGet(fe,'mkeepfibers',fiberList) +% val = fe.life.Mfiber(:,varargin{1}); + +% case {'miso'} +% % Isotropic portion of M matrix +% % returns the matrix for the full model or for a subset of voxels +% % +% % Miso = feGet(fe,'M iso') +% % Miso = feGet(fe,'M iso',voxelsIndices) +% % Miso = feGet(fe,'M iso',coords) +% if isempty(varargin) +% % Return the whole M iso +% val = feBuildSparseBlockDiag(feGet(fe,'nBvecs'),feGet(fe,'nVoxels')); +% else +% val = feBuildSparseBlockDiag(feGet(fe,'nBvecs'),length(feGet(fe,'voxelsindices',varargin))); +% end + + case {'voxel2fnpair','voxel2fibernodepair','v2fnp'} + % Pairing of fibers and nodes in each voxel. + % + % v2fnp = feGet(fe,'v2fnp'); + if isempty(fe.life.voxel2FNpair) + fprintf('[%s] fe.life.voxel2FNpair is empty, can be computed as: \nfe = feSet(fe,''v2fnp'',feGet(fe,''fg img''),''v2fn'',feGet(fe,''roi coords'')',mfilename); + return + end + val = fe.life.voxel2FNpair; + + case {'tensors','fibers tensors'} + % Tensors computed for each node and fiber in a set of voxels. + % + % t = feGet(fe,'tensors') + % t = feGet(fe,'tensors',voxelsIndices); + % t = feGet(fe,'tensors',coords); + if isempty(varargin) + val = fe.life.fibers.tensors; + else + vv = feGet(fe,'voxelsindices',varargin); + val = cell(size(vv)); + for ff = 1:length(vv) + val{ff} = fe.life.fibers.tensors{vv(ff)}; + end + end + + case {'voxeltensors','voxtensors','voxq'} + % Get all the tensors in a signle voxel + % + % val = feGet(fe,'voxtensors',voxelIndex) + % val = feGet(fe,'voxtensors',coord) + + % Index for the voxel + vv = feGet(fe,'voxelsindices',varargin); + + % The indexes of the voxeles used, to build LiFE. + usedVoxels = feGet(fe,'usedVoxels'); + voxIndex = usedVoxels(vv); + nNodes = feGet(fe,'nNodes'); + + % Get the tensors for each node in each fiber going through this voxel: + val = zeros(nNodes(voxIndex), 9); % Allocate space for all the tensors (9 is for the 3 x 3 tensor components) + for ii = 1:nNodes(voxIndex) % Get the tensors + val(ii,:) = fe.life.fibers.tensors{fe.life.voxel2FNpair{voxIndex}(ii,1)} ... + (fe.life.voxel2FNpair{voxIndex}(ii,2),:); + end + + case {'nnodes','numofnodes'} + % Total number of nodes in each voxel The voxel2FN pairs are row size + % equals number of nodes and column size is always 2. The entries of + % the first column are the fiber number. The entries in the second + % column are the node of the fiber inside the voxel. + % + % val = feGet(fe,'n nodes'); + % val = feGet(fe,'n nodes',voxelsIndices); + % val = feGet(fe,'n nodes',coords); + if ~isempty(fe.life.voxel2FNpair) + [val, ~] = cellfun(@size,fe.life.voxel2FNpair); + val = val(feGet(fe,'voxelsindices',varargin)); + end + + case {'numberofuniquefibersbyvoxel','uniquefnum'} + % Return the total number of fibers for all the voxels or in a set of + % voxels + % + % nFibers = feGet(fe,'uniquefnum'); % all the voxels + % nFibers = feGet(fe,'uniquefnum',[1 2 3 4]); % for some the voxels, + % % specified by indexes + % nFibers = feGet(fe,'uniquefnum',coords); % for some the voxels, + % % specified by coordinates + val = fe.life.fibers.unique.num(feGet(fe,'voxelsindices',varargin)); + + case {'indextouniquefibersbyvoxel','uniquef'} + % Return the indexes of the fibers for all the voxels or in a set of + % voxels. + % + % idxFibers = feGet(fe,'uniquef'); % all the voxels + % idxFibers = feGet(fe,'uniquef',[1 2 3 4]); % for some the voxels, + % % specified by indexes + % idxFibers = feGet(fe,'uniquef',coords); % for some the voxels, + % % specified by coordinates + vxIndex = feGet(fe,'voxels indices',varargin); + val = cell(length(vxIndex),1); + for ii = 1:length(vxIndex) + val{ii} = fe.life.fibers.unique.index{vxIndex(ii)}; + end + + case {'numberoftotalfibersbyvoxels','totfnum'} + % Return the total number of fibers for all the voxels or in a set of + % voxels + % + % nFibers = feGet(fe,'totfnum'); % all the voxels + % nFibers = feGet(fe,'totfnum',[1 2 3 4]); % for some the voxels, + % % specified by indexes + % nFibers = feGet(fe,'totfnum',coords); % for some the voxels, + % % specified by coordinates + val = fe.life.fibers.total.num(feGet(fe,'voxels indices',varargin)); + + case {'indexoftotalfibersbuvoxel','totf'} + % Return the indexes of the fibers for all the voxels or in a set of + % voxels + % + % idxFibers = feGet(fe,'totf'); % all the voxels + % idxFibers = feGet(fe,'totf',[1 2 3 4]); % for some the voxels, + % % specified by indexes + % idxFibers = feGet(fe,'totfibers',coords); % for some the voxels, + % % specified by coordinates + vxIndex = feGet(fe,'voxels indices',varargin); + val = cell(length(vxIndex),1); + for ii = 1:length(vxIndex) + val{ii} = fe.life.fibers.total.index{vxIndex(ii)}; + end + + case {'nfibers'} + % Return the number of fibers in the model. + % + %val = size(fe.life.fibers,2); + val = size(fe.fg.fibers,1); + + case {'natoms'} + % Return the number of atoms in the dictionary + val = size(fe.life.M.DictSig,2); + + case {'orient'} + % Return the number of atoms in the dictionary + val = fe.life.M.orient; + + case {'isoweights','weightsiso','meanvoxelsignal'} + % Weights of the isotropic voxel signals, this is the mean signal in + % each voxel. + % + % val = feGet(fe,'iso weights'); + % val = feGet(fe,'iso weights'coords) + % val = feGet(fe,'iso weights',voxelIndices) + val = feGet(fe,'Miso') \ feGet(fe,'dsig full')'; + val = val(feGet(fe,'voxelsindices',varargin)); + + case {'voxisoweights','voxweightsiso','voxmeanvoxelsignal'} + % Weights of the isotropic voxel signals, this is the mean signal in + % each voxel. + % Organized nBvecs x nVoxels + % + % val = feGet(fe,'iso weights'); + % val = feGet(fe,'iso weights'coords) + % val = feGet(fe,'iso weights',voxelIndices) + val = feGet(fe,'Miso') \ feGet(fe,'dsig full')'; + val = repmat(val,1,feGet(fe,'nbvecs'))'; + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:,feGet(fe,'voxelsindices',varargin)); + end + + case {'dsigiso','isodsig'} + % mean signalin each voxel, returned for each diffusion direction: + % size(nBvecsxnVoxels, 1). + % + % val = feGet(fe,'iso disg'); + % val = feGet(fe,'iso disg',coords) + % val = feGet(fe,'iso dsig',voxelIndices) + val = feGet(fe,'iso weights'); + val = repmat(val,1,feGet(fe,'nbvecs'))'; + val = val(:); + + case {'fiberweights'} + % Weights of the fiber component. For all the fibers or a subset of + % them. + % + % w = feGet(fe,'fiber weights') + % w = feGet(fe,'fiber weights',fiberIndices) + + % If the model was not fit yet, fit it, install the fit and then return + % the weights. + if ~isfield(fe.life,'fit') + fprintf('[%s] fe.life.fit is empty, can be computed as: \nfeSet(fe,''fit'',feFitModel(feGet(fe,''Mfiber''), feGet(fe,''dsigdemeaned''),''sgdnn''))',mfilename); + return + end + + % Get the weights + if ~isempty(varargin) % subselect the weights for the requested fibers + val = fe.life.fit.weights(varargin{1}); + else % Return all of them + val = fe.life.fit.weights; + end + + case {'fiberweightstest'} + % Weights of the fiber component with a subset of the fibers' weigth + % set to zero. This can be used to test the loss in RMSE for the + % connectome when a subset of fibers is removed, but the connectome is + % not fitted again. + % + % w = feGet(fe,'fiber weights test',fiberIndices) + + % If the model was not fit yet, fit it, install the fit and then return + % the weights. + if ~isfield(fe.life,'fit') + fprintf('[%s] fe.life.fit is empty, can be computed as: \nfeSet(fe,''fit'',feFitModel(feGet(fe,''Mfiber''), feGet(fe,''dsigdemeaned''),''sgdnn''))',mfilename); + return + end + + % Get the weights + if ~isempty(varargin) % subselect the weights for the requested fibers + val = fe.life.fit.weights; + val(varargin{1}) = 0; + else % A set of fiber weights is required as input + error('[%s] Indices to a subset of fiber-weights must be passed in w = feGet(fe,''fiber weights test'',fiberIndices))',mfilename); + end + + case {'fiberweightstestvoxelwise'} + % Weights of the fiber component with a subset of the fibers' weigth + % set to zero. This can be used to test the loss in RMSE for the + % connectome when a subset of fibers is removed, but the connectome is + % not fitted again. + % + % w = feGet(fe,'fiber weights test voxel wise',fiberIndices) + + % If the model was not fit yet, fit it, install the fit and then return + % the weights. + if ~isfield(fe.life,'voxfit') + fprintf('[%s] fe.life.fit is empty, can be computed as: \nfeSet(fe,''fit'',feFitModel(feGet(fe,''Mfiber''), feGet(fe,''dsigdemeaned''),''sgdnn''))',mfilename); + return + end + + % Get the weights + if ~isempty(varargin) % subselect the weights for the requested fibers + val = fe.life.voxfit.weights; + val(:,varargin{1}) = 0; + else % A set of fiber weights is required as input + error('[%s] Indices to a subset of fiber-weights must be passed in\nw = feGet(fe,''fiber weights test voxel wise'',fiberIndices))',mfilename); + end + + case {'dsigmeasured','dsigfull'} + % Measured signal in VOI, this is the raw signal. not demeaned + % + % dSig = feGet(fe,'dSig full') + val = fe.life.dSig; + % Return a subset of voxels + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'diffusionsignaldemeaned','dsigdemeaned'} + % Measured signal in VOI, demeaned, this is the signal used for the + % fiber-portion of the M model. + % + % dSig = feGet(fe,'dsigdemeaned'); + % dSig = feGet(fe,'dsigdemeaned',[1 10 100]); + % dSig = feGet(fe,'dsigdemeaned',coords); + nVoxels = feGet(fe,'nVoxels'); + nBvecs = feGet(fe,'nBvecs'); + dSig = reshape(fe.life.diffusion_signal_img',[1,nVoxels*nBvecs]); + val = (dSig - reshape(repmat( ... + mean(reshape(dSig, nBvecs, nVoxels),1),... + nBvecs,1), size(dSig)))'; + % Return a subset of voxels + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'dsigrowssubset','diffusionsignaldemeanedinsubsetofrows'} + % Get the demeaned signal for a subset of rows. + % Useful for cross-validation. + % + % dSig = feGet(fe,'dsigrowssubset',voxelsList); + dSig = feGet(fe,'dsigdemeaned'); + for vv = 1:length(voxelsList) + val(feGet(fe,'voxel rows',vv)) = dSig(feGet(fe,'voxel rows',voxelList(vv))); + end + + case {'psigfiber', 'fiberpsig','fiberpredicted','dsigpredictedfiber'} + % Predicted signal of fiber alone (demeaned). + % + % pSig = feGet(fefeGet(fe,'fiber weights','pSig fiber'); + % pSig = feGet(fe,'pSig fiber',coords); + % pSig = feGet(fe,'pSig fiber',voxelIndices); + %val = feGet(fe,'Mfiber')*feGet(fe,'fiber weights'); + val = M_times_w(feGet(fe,'Mfiber'),feGet(fe,'fiber weights')); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'uniquefibersindicesinroi'} + % Find the unique fibers indices in the FE roi. + % Thisis necessary sometimes after changing the number of voxels in an + % FE structure, as it is performed by feConnectomeReduceVoxels.m + % + % FibInRoi = feGet(fe,'uniquefibersinroi'); + + % Get all the unique fibers in each voxel + uniquefvx = fefgGet(feGet(fe,'fibers img'), ... + 'uniquefibersinvox', ... + feGet(fe,'roi coords')); + val = []; + for ivx = 1:length(uniquefvx) + val = [val; uniquefvx{ivx}]; + end + val = unique(val); + + case {'weightsinroi'} + % Find the weights of the fibers in a specified volume. + % + % We compute the following values: + % (1) The number of unique fibers in the volume + % (2) The weights for the fibers in the roi + % + % wFibInRoi = feGet(fe,'weightsinroi'); + + % Get all the unique fibers in each voxel + FibInRoi = feGet(fe,'uniquefibersindicesinroi'); + + % extract the fber weights obtained in a LiFE fit + w = feGet(fe,'fiber weights'); + + % Return only the ones for the fibers in this roi + val = w(unique( FibInRoi )); + + case {'fiberdensity'} + % Fiber density statistics. + % + % Computes the fiber density (how many fibers in each voxel) + % + % We compute the following values: + % (1) The number of fibers in each voxel + % (2) The number of unique fibers with non-zero weights + % (3) The sum of the weights in each voxel + % (4) The mean of the weights in each voxel + % (5) The variance of the weigths in each voxel + % + % pSig = feGet(fe,'fiberdensity'); + + % Get the unique fibers in each voxel + uniquefvx = fefgGet(feGet(fe,'fibers img'), ... + 'uniquefibersinvox', ... + feGet(fe,'roi coords')); + + % extract the fber weights obtained in a LiFE fit + w = feGet(fe,'fiber weights'); + + % Compute the fiber density in three wasy: + % (1) The number of fibers in each voxel + % (2) The number of unique fibers with non-zero weights + % (3) The sum of the weights in each voxel + % (4) The mean of the weights in each voxel + % (5) The variance of the weigths in each voxel + val = nan(length(uniquefvx),5); + for ivx = 1:length(uniquefvx) + + % Number of fibers in each voxel + val(ivx,1) = length(uniquefvx{ivx}); + + % Number of fibers in ech voxel with non-zero weight + val(ivx,2) = length(uniquefvx{ivx}(w(uniquefvx{ivx}) > 0)); + + % Sum of fiber weights in each voxel + val(ivx,3) = sum(w(uniquefvx{ivx})); + + % Mean of fiber weights in each voxel + val(ivx,4) = nanmedian(w(uniquefvx{ivx})); + + % Var of fibers in each voxel + val(ivx,5) = nanvar(w(uniquefvx{ivx})); + end + +% case {'psigfibertest'} +% % Predicted signal (demeaned) with a subset of fibers' weights set to 0. +% % This can be used to test the loss in RMSE for the connectome when a +% % subset of fibers is removed, but the connectome is not fitted again. +% % +% % pSig = feGet(fe,'pSig fiber test',fiberIndices); +% % pSig = feGet(fe,'pSig fiber test',fiberIndices,voxelIndices); +% % pSig = feGet(fe,'pSig fiber test',fiberIndices,coords); +% if ~isempty(varargin) +% val = feGet(fe,'Mfiber')*feGet(fe,'fiber weights test',varargin{1}); +% +% % Now select a subset of voxels if requested +% if (length(varargin) == 2) +% % voxelIndices = feGet(fe,'voxelsindices',varargin); +% % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); +% % val = val(voxelRowsToKeep,:); +% val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin{2}))); +% end +% else +% error('[%s] A set f fiber indiced must be passed in. pSig = feGet(fe,''pSig fiber test'',fiberIndices))',mfilename); +% end + +% case {'psigfibertestvoxelwise'} +% % Predicted signal (demeaned) with a subset of fibers' weights set to 0. +% % This can be used to test the loss in RMSE for the connectome when a +% % subset of fibers is removed, but the connectome is not fitted again. +% % +% % pSig = feGet(fe,'pSig fiber test voxel wise',fiberIndices); +% % pSig = feGet(fe,'pSig fiber test voxel wise',fiberIndices,voxelIndices); +% % pSig = feGet(fe,'pSig fiber test voxel wise',fiberIndices,coords); +% +% if ~isempty(varargin) +% nVoxels = feGet(fe,'nvoxels'); +% w = feGet(fe,'fiber weights test voxel wise',varargin{1}); % Weights with a subset set to 0 +% val = cell(nVoxels,1); +% for ivox = 1:nVoxels +% % Predict the signal. +% val{ivox} = feGet(fe,'Mfiber',ivox)*w(ivox,:)'; +% end +% +% feOpenLocalCluster +% % Reorganize the signal into a vector +% val = vertcat(val{:})'; +% +% % Now select a subset of voxels if requested +% if (length(varargin) == 2) +% % voxelIndices = feGet(fe,'voxelsindices',varargin); +% % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); +% % val = val(voxelRowsToKeep,:); +% val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin{2}))); +% end +% else +% error('[%s] A set f fiber indiced must be passed in. pSig = feGet(fe,''pSig fiber test'',fiberIndices))',mfilename); +% end +% +% case {'predictedsignalfull','psigfull'} +% % Predicted measured signal from both fiber and iso +% % +% % pSig = feGet(fe,'pSig full') +% % pSig = feGet(fe,'pSig full',coords) +% % pSig = feGet(fe,'pSig full',voxelIndices) +% val = [feGet(fe,'M fiber'), feGet(fe,'M iso')] * feGet(fe,'full weights'); +% if ~isempty(varargin) +% % voxelIndices = feGet(fe,'voxelsindices',varargin); +% % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); +% % val = val(voxelRowsToKeep,:); +% val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); +% end + + case {'fullweights'} + % The fiber and isotropic weights as a long vector + % + % w = feGet(fe,'fullweights') + val = [feGet(fe,'fiber weights'); feGet(fe,'iso weights')]; + + case {'fiberweightsvoxelwise'} + % The woxels returned by a fit of LiFE by voxel/fiber + % + % w = feGet(fe,'fiberweightsvoxelwise') + val = fe.life.voxfit.weights; + + case {'psigfvoxelwise'} + % Predict the diffusion signal for the fiber component + % with the voxel-wise fit of LiFE + % + % pSig = feGet(fe,'psigfvoxelwise') + % pSig = feGet(fe,'psigfvoxelwise',coords) + % pSig = feGet(fe,'psigfvoxelwise',voxelIndices) + + if ~isfield(fe.life,'voxfit'), + error('[%s] Cannot find voxel-wise fit.\nTo fit the model voxel-wise run:\nfe = feFitModelByVoxel(fe)\n',mfilename); + end + val = fe.life.voxfit.psig; + + % Get a subset of voxels. + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'psigfvoxelwisebyvoxel'} + % Predict the diffusion signal for the fiber component + % with the voxel-wise fit of LiFE, return the an array of pSigXnVoxel + % + % pSig = feGet(fe,'psigfvoxelwisebyvoxel') + % pSig = feGet(fe,'psigfvoxelwisebyvoxel',coords) + % pSig = feGet(fe,'psigfvoxelwisebyvoxel',voxelIndices) + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'psigfvoxelwise'), nBvecs, nVoxels); + + case {'totalr2'} + % Return the global R2 (fraction of variance explained) of the full life + % model. + % + % R2 = feGet(fe,'total r2'); + + % measured = feGet(fe,'dsigdemeaned'); + % predicted = feGet(fe,'fiber p sig'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGet(fe,'diffusion signal demeaned') - ... + feGet(fe,'fiber predicted')).^2 ) ./ ... + sum((feGet(fe,'diffusion signal demeaned') - ... + mean(feGet(fe,'diffusion signal demeaned'))).^2) )); + + case {'totalr2voxelwise'} + % Return the global R2 (fraction of variance explained) of the full life + % model from a voxel-wise fit. + % + % R2 = feGet(fe,'total r2 vocel wise'); + + % measured = feGet(fe,'dsigdemeaned'); + % predicted = feGet(fe,'p sig f voxel wise'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGet(fe,'diffusion signal demeaned') - ... + feGet(fe,'psigfvoxelwise')').^2 ) ./ ... + sum((feGet(fe,'diffusion signal demeaned') - ... + mean(feGet(fe,'diffusion signal demeaned'))).^2) )); + + case {'totpercentvarianceexplained','totpve'} + % Percent variance explained + % + % R2 = feGet(fe,'explained variance') + val = 100 * feGet(fe,'total r2'); + + case {'rmsetotal','totalrmse'} + % Root mean squared error of the LiFE fit to the whole data + % + % rmse = feGet(fe,'rmse') + val = sqrt(mean((feGet(fe,'diffusion signal demeaned') - ... + feGet(fe,'pSig fiber')).^2)); + + case {'totalrmsevoxelwise'} + % Root mean squared error of the LiFE fit to the whole data from a + % vocel-wise fit + % + % rmse = feGet(fe,'rmse') + val = sqrt(mean((feGet(fe,'diffusion signal demeaned') - ... + feGet(fe,'pSig f voxelwise')').^2)); + + case {'ressigfiber'} + % Residual signal fiber prediction - measured_demeaned. + % + % res = feGet(fe,'res sig fiber') + val = (feGet(fe,'dsigdemeaned') - feGet(fe,'psig fiber')); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'ressigfull'} + % Residual signal full model prediction - measured signal. + % + % res = feGet(fe,'res sig full'); + % res = feGet(fe, 'res sig full',coords); + % res = feGet(fe, 'res sig full',voxelIndex); + val = (feGet(fe,'dsig full') - feGet(fe,'psig full')'); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'ressigfullvoxelwise'} + % Residual signal full model prediction from a multi-voxel fit. + % + % res = feGet(fe,'res sig full voxfit'); + % res = feGet(fe, 'res sig full voxfit',coords); + % res = feGet(fe, 'res sig full voxfit',voxelIndex); + %tic,val = feGet(fe,'dsig demeaned') - feGet(fe,'psigfvoxelwise') + feGet(fe,'dsigiso');toc + val = feGet(fe,'dsig full') - feGet(fe,'psigfvoxelwise')'; + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'fiberressigwithmean'} + % Residual signal fiber model prediction - demeaned measured signal + % with added mean signal. VECTOR FORM. + % + % This is used to reconstruct an image (volume) to be used for the + % refinement process. + % + % res = feGet(fe,'fiber res sig with mean'); + + % predicted = feGet(fe,'psig fiber'); + % measured = feGet(fe,'dsigdemeaned'); + % val = (measured_full - predicted demeaned); + val = (feGet(fe,'dsig full')' - feGet(fe,'psig fiber')); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'predictedfibersignalvoxel','psigfvox'} + % Predicted signal by the fiber model in a set of voxels. + % + % Vox subfield stores per voxel within the VOI + % The pSig has size of the dwi. + % It is stored as val = pSig(X,Y,Z,Theta) + % + % pSig = feGet(fe, 'pSig fiber by voxel'); + % pSig = feGet(fe, 'pSig fiber by voxel',coords); + % pSig = feGet(fe, 'pSig fiber by voxel',voxelIndex); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'pSig fiber'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin)); + + case {'predictedfullsignalvoxel','psigfullvox'} + % Predicted signal by the full model in a set of voxeles. + % + % Vox subfield stores per voxel within the VOI + % The pSig has size of the dwi. + % It is stored as val = pSig(X,Y,Z,Theta) + % + % pSig = feGet(fe, 'pSig full by voxel'); + % pSig = feGet(fe, 'pSig full by voxel',coords); + % pSig = feGet(fe, 'pSig full by voxel',voxelIndex); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'pSig full'), nBvecs, nVoxels); + + case {'voxelr2','r2vox','voxr2','r2byvoxel'} + % Return a column vector of the proportion of variance explained in + % each voxel. + % + % R2byVox = feGet(fe,'voxr2'); + % R2byVox = feGet(fe,'voxr2',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + nBvecs = feGet(fe,'nBvecs'); + val = (1 - (sum((measured - predicted).^2 ) ./ ... + sum((measured - repmat(mean(measured), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zero','r2voxzero','voxr2zero','r2byvoxelzero'} + % Return a column vector of the proportion of variance explained in + % each voxel. (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGet(fe,'voxr2zero'); + % R2byVox = feGet(fe,'voxr2zero',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + val = (1 - (sum((measured - predicted).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelvarianceexplained','varexpvox','voxvarexp','varexpbyvoxel'} + % Return the percent of varince explained in each voxel. + % + % R2byVox = feGet(fe,'var exp by voxel'); + % R2byVox = feGet(fe,'var exp by voxel',coords); + val = 100.*feGet(fe,'voxr2'); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2voxelwise','r2voxvoxelwise','voxr2voxelwise'} + % Return a column vector of the proportion of variance explained in + % each voxel. + % + % R2byVox = feGet(fe,'voxr2voxelwise'); + % R2byVox = feGet(fe,'voxr2voxewise',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'psig f voxel wise by voxel'); + nBvecs = feGet(fe,'nBvecs'); + val = (1 - (sum((measured - predicted).^2 ) ./ ... + sum((measured - repmat(mean(measured), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zerovoxelwise','voxr2zerovoxelwise'} + % Return a column vector of the proportion of variance explained in + % each voxel. (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGet(fe,'voxr2zerovoxelwise'); + % R2byVox = feGet(fe,'voxr2zerovoxelwise',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'psig f voxel wise by voxel'); + val = (1 - (sum((measured - predicted).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelvarianceexplainedvoxelwise','varexpvoxvoxelwise'} + % Return the percent of varince explained in each voxel. + % + % R2byVox = feGet(fe,'var exp by voxel'); + % R2byVox = feGet(fe,'var exp by voxel',coords); + val = 100.*feGet(fe,'voxr2voxelwise'); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'dsigdemeanedbyvoxel','dsigdemeanedvox'} + % Demeaned diffusion signal in each voxel + % + % dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel'); + % dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel',coords); + % dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel',vxIndex); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'dsigdemeaned'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin)); + + case {'dsigfullbyvoxel','dsigfullvox','voxdsigfull'} + % Full (measured) signal in each voxel + % + % dSigByVoxel = feGet(fe,'dSig full by Voxel'); + % dSigByVoxel = feGet(fe,'dSig full by Voxel',coords); + % dSigByVoxel = feGet(fe,'dSig full by Voxel',vxIndex); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'dSig full'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'voxelrmse','voxrmse'} + % A volume of RMSE values + % + % RMSE = feGet(fe,'vox rmse') + % RMSE = feGet(fe,'vox rmse',coords) + % RMSE = feGet(fe,'vox rmse',vxIndex) + measured = feGet(fe,'dsigdemeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + val = sqrt(mean((measured - predicted).^2,1)); + val = val(feGet(fe,'voxelsindices',varargin)); + + case {'voxelrmsevoxelwise','voxrmsevoxelwise'} + % A volume of RMSE values optained with the voxel-wise (voxelwise) fit. + % + % RMSE = feGet(fe,'vox rmse voxelwise') + % RMSE = feGet(fe,'vox rmse voxelwise',coords) + % RMSE = feGet(fe,'vox rmse voxelwise',vxIndex) + measured = feGet(fe,'dsigdemeaned by voxel'); + predicted = feGet(fe,'pSig f voxel wise by voxel'); + + val = sqrt(mean((measured - predicted).^2,1)); + val = val(feGet(fe,'voxelsindices',varargin)); + + case {'voxelrmsetest','voxrmsetest'} + % A volume of RMSE values with a subset of fibers' weights set to 0. + % + % RMSE = feGet(fe,'vox rmse',fiberIndices) + % RMSE = feGet(fe,'vox rmse',fiberIndices,coords) + % RMSE = feGet(fe,'vox rmse',fiberIndices,voxelIndex) + measured = feGet(fe,'dsigdemeaned by voxel'); + % Reshape the predicted signal by voxles + predicted = reshape(feGet(fe,'pSig fiber test',varargin{1}), feGet(fe,'nBvecs'), feGet(fe,'nVoxels')); + val = sqrt(mean((measured - predicted).^2,1)); + + if length(varargin) == 2 + val = val(feGet(fe,'voxelsindices',varargin)); + end + + case {'residualsignalfibervoxel','resfibervox'} + % Fibers' residual signal by voxel + % + % res = feGet(fe,'res sig fiber vox') + % res = feGet(fe,'res sig fiber vox',coords) + % res = feGet(fe,'res sig fiber vox',vxIndex) + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'res sig fiber'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'residualsignalfullvoxel','resfullvox'} + % Full (measured) residual signal by voxel + % + % res = feGet(fe,'res sig full vox') + % res = feGet(fe,'res sig full vox',coords) + % res = feGet(fe,'res sig full vox',vxIndex) + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'res sig full'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'fiberressigwithmeanvoxel'} + % Residual signal fiber model prediction - demeaned measured signal + % with added mean signal. VOXEL FORM (nBvecs x nVoxel). + % + % This is used to reconstruct an image (volume) to be used for the + % refinement process. + % + % res = feGet(fe,'fiber res sig with mean'); + + % predicted = feGet(fe,'psig fiber'); + % measured = feGet(fe,'dsigdemeaned'); + % val = (measured - predicted) + (measured_full - measured); + val = feGet(fe,'fiberressigwithmean'); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(val, nBvecs, nVoxels); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:, feGet(fe,'return voxel indices',varargin)); + end + + case {'fiberressigwithmeanvox','resfibermeanvox'} + % Fibers' residual signal by voxel with mean signal added (with added + % isotropic component). + % + % This is used to compute the residual signal for the refinement. + % + % res = feGet(fe,'fiber res sig with mean vox') + % res = feGet(fe,'fiber res sig with mean vox',coords) + % res = feGet(fe,'fiber res sig with mean vox',vxIndex) + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'fiber res sig with mean'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'voxelsindices','returnvoxelindices','voxelindexes''returnvoxelindexes'} + % Given an VOI or a set of indices to voxels returns the indices of the matching voxels inside the big + % volume, which ordinarily represents the full connectome. + % + % voxelIndices = feGet(fe,'voxelsindices',coords) + % voxelIndices = feGet(fe,'voxelsindices',voxelIndices) + % IMPORTANT: Indices MUST be a column vector for this + % code to work. + % + % coords is a Nx3 set of coordinates in image space + % voxelIndices is a vector of 1's and 0's, there is a one for each + % location the the connectome coordinates for which there is a match in + % the coords + % + varargin = varargin{1}; + if ( ~isempty(varargin) ) + if ( size(varargin{1},2) == 3 ) + % If a set of coordinates were passed in we return the indices. + val = logical(feGet(fe,'find voxels',varargin{1})); + else + % If indices were passed in, we sort and return them. + val = sort(varargin{1}); + end + else + % If no coordinates were passed at all, we return all the indices. + val = true(feGet(fe,'n voxels'),1); + end + + case {'findvoxels','findvoxelindexes','findvoxelsinconnectome','findvoxelsinconnectomeroi', ... + 'voxel2index','coords2index'} + % Given an VOI finds the indices of the matching voxels inside the big + % volume, which ordinarily represents the full connectome. + % + % foundVoxels = feGet(fe,'find voxels',coords) + % + % coords is a Nx3 set of coordinates in image space + % foundVoxels is a vector of 1's and 0's, there is a one for each + % location the the connectome coordinates for which there is a match in + % the coords + + % Compute the values for a subset of voxels + if isempty(varargin) + % If no coordinates were passed at all, we return all the indices. + val = ones(feGet(fe,'n voxels'),1); + else + % The stored coordinates are at a resolution of the image, typically + % 2mm isotropic. The VOI should also be in image resolution. + % ---- Franco: + % This is how I had it. I think it is worng: + % val = ismember(feGet(fe,'roi coords'), varargin{1}, 'rows'); % This is slow + % This is hwo I think it should be: + [~,val] = ismember(varargin{1}, feGet(fe,'roi coords'),'rows'); % This is slow + end + + case {'voxelcoords2voxelrows','coords2rows'} + % Given a set of VOI coords finds the row numbers of the Model matrix + % (or equivalently the dSig vector) that represent the data for this + % set of VOI coords. + % + % foundVoxels = feGet(fe,'coords 2 rows',coords) + % + % coords - a Nx3 set of coordinates in image space + % foundVoxels - a binary vector that is 1 for each Model matrix row + % that corresponds to at least one of the coords. + val = feGet(fe,'voxel rows',find(feGet(fe,'find voxels',varargin{1}))); + + % ------ Spatial coordinate transforms for voxels and fg to coordinate frames + case {'xformimg2acpc','xform2acpc','img2acpc','img2acpcxform'} + % Quaternian transformation from IMAGE space to ACPC space. + % + % xform = feGet(fe,'xform') + val = fe.life.xform.img2acpc; + case {'xformacpc2img','xform2img','acpc2img','acpc2imgxform'} + % Quaternian transformation from ACPC space to IMAGE space. + % + % xform = feGet(fe,'xform') + val = fe.life.xform.acpc2img; + case {'volumesize','dims','dim','imagedim'} + % Dimensions of the DW volume. + % + % dim = feGet(fe,'dims') + val = fe.life.imagedim; + case {'mapsize'} + % Dimensions of the maps of parameters and results. + % + % dims = feGet(fe, 'mapsize') + val = fe.life.imagedim(1:3); + + case {'anatomyfile'} + % Path to the 3D Anatomy Volume. + % anatomyfile = feGet(fe, 'anatomy file') + val = fe.path.anatomy; + case 'dtfile' + % Diffusion weighted file used for testing results + % dtfile = feGet(fe,'dtfile') + val = fe.path.dtfile; + case 'model' + % Multiway decomposition model elements + val = fe.life.M; + case 'lists' + % atoms, voxels and Nelem lists (to be revised for future elimination) + val.atoms = fe.life.fibers.atoms_list; + val.voxels = fe.life.fibers.voxels_list; + val.Nelem = fe.life.fibers.Nelem; + case 's0_img' + val = fe.life.diffusion_S0_img; + case 'nelem' + val = fe.life.fibers.Nelem; + case 'nphi' + val = fe.life.M.Nphi; + case 'ntheta' + val = fe.life.M.Ntheta; + + + otherwise + help('feGet') + fprintf('[feGet] Unknown parameter << %s >>...\n',param); + keyboard +end + +end % END MAIN FUNCTION diff --git a/fe/feGetOLD.m b/fe/feGetOLD.m new file mode 100755 index 0000000..216580f --- /dev/null +++ b/fe/feGetOLD.m @@ -0,0 +1,1628 @@ +function val = feGetOLD(fe,param,varargin) +% Get function for fascicle evaluation structure +% +% val = feGet(fe,param,varargin) +% +% +% INPUTS: +% Coords - Nx3 set of coordinates in image space +% voxelIndices - Vector of 1's and 0's, there is a one for each +% location the the connectome coordinates for which there is +% a match in the coords +% +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com +% +% +%---------- List of arguments ---- +% Name of the current fe structure. +% name = feGet(fe,'name') +%---------- +% The type of objes (always, fascicle evaluation) +% type = feGet(fe,'type') +%---------- +% Structure of parameters and results from LIFE analysis +% life = feGet(fe,'life') +%---------- +% Return the connectome (fiber group) in image coordinates. +% fg = feGEt(fe,'fg img') +%---------- +% return the connectome in acpc coordinates. +% fg = feGet(fg,'fg acpc') +%---------- +% Return the VOI comprised by the full connectome. +% roi = feGet(fe,'roi') +%---------- +% Transforms between coords for fg, roi, and dwi data +% xform = feGet(fe,'xform') +%---------- +% Load the diffusion weighted data. +% dwi = feGet(fe,'dwi') +%---------- +% Return the path to the diffusion weighted data file. +% dwiFile = feGet(fe,'dwifile') +%---------- +% Load the repeated-measure diffusion weighted data. +% dwi = feGet(fe,'dwirepeat') +%---------- +% Load the repeated measure of the diffusion weighted data. +% dwiFile = feGet(fe,'dwirepeatfile') +%---------- +% Directory where the LiFe structes are saved by defualt. +% sdir = feGet(fe,'savedir'); +%---------- +% Diffusion directions. +% val = feGet(fe,'bvecs'); +%---------- +% Indices to the diffusion directions in the DWi 4th Dimension. +% val = feGet(fe,'bvecs indices'); +%---------- +% Number of B0's +% val = feGet(fe,'n bvals'); +%---------- +% B0 Values. +% bval = feGet(fe,'bvals') +%---------- +% Returns a nVoxels X nBvecs array of measured diffusion signal +% val = feGet(fe,'dsiinvox'); +% val = feGet(fe,'dsiinvox',voxelsIndices); +% val = feGet(fe,'dsiinvox',coords); +%---------- +% Returns a nVoxels X nBvecs array of demeaned diffusion signal +% val =feGet(fe,'dsiinvoxdemeaned'); +% val =feGet(fe,'dsiinvoxdemeaned',voxelsIndices); +% val =feGet(fe,'dsiinvoxdemeaned',coords); +%---------- +% Get the diffusion signal at 0 diffusion weighting (B0) for this voxel +% val = feGet(fe,'b0signalvoxel'); +% val = feGet(fe,'b0signalvoxel',voxelIndex); +% val = feGet(fe,'b0signalvoxel',coords); +%---------- +% Return a subset of fibers from the conenctome. +% fg = feGet(fe,'fiberssubset',fiberList); +%---------- +% Return the coordinates of the VOI comprised in the connectome. +% Always in image space. +% coords = feGet(fe,'roi coords') +%---------- +% Number of voxels in the connectome/VOI. +% nVoxels = feGet(fe,'n voxels') +%---------- +% Indexes of actually used voxels. +% These can be different than the number of voxels in the VOI in case some +% voxels have no fibers in them. +% +% TO BE DEPRECATED. +% indxUsedVx = feGet(fe,'index of used voxels') +%---------- +% Number of actually used voxels. +% This can be less than the number of voxels in the VOI in case some +% voxels have no fibers in them. +% +% TO BE DEPRECATED. +% nUsedVx = feGet(fe,'index of used voxels') +%---------- +% Returns the first index to a voxel in the dSig vector. +% The dSig vector is 1:nBvecs*nVoxels. +% val = feGet(fe,'start rows') +%---------- +% Return the rows corresponding to a set of voxels. +% rows = feGet(fe,'voxel rows',idxVoxel) +%---------- +% Return the model (M matrix), or a subset of it. +% Mfiber = feGet(fe,'M fiber'); +% Mfiber = feGet(fe,'model',voxelsIndices); +% Mfiber = feGet(fe,'model',coords); +%---------- +% Return a subset of measurements from the fiber portion of M matrix +% The rows of M are specified. Remember that the rows refer to a +% combination of voxel and measurement direction and potentially in the +% future a b-value. Hence, the rows are not specific to a voxel. +% Mfiber = feGet(fe,'mfiber subset',rowsToKeep); +%---------- +% Pairing of fibers and nodes in each voxel. +% v2fnp = feGet(fe,'v2fnp'); +%---------- +% Tensors computed for each node and fiber in a set of voxels. +% t = feGet(fe,'tensors') +% t = feGet(fe,'tensors',voxelsIndices); +% t = feGet(fe,'tensors',coords); +%---------- +% Get all the tensors in a single voxel. +% val = feGet(fe,'voxtensors',voxelIndex) +% val = feGet(fe,'voxtensors',coord) +%---------- +% Returns the model (M) with only a subset of columns (fibers). +% fiberList is a vector of indexes, e.g, [1 10 100] +% M = feGet(fe,'keepfibers',fiberList) +%---------- +% Isotropic portion of M matrix. Returns the matrix for the full model or +% for a subset of voxels. +% Miso = feGet(fe,'M iso') +% Miso = feGet(fe,'M iso',voxelsIndices) +% Miso = feGet(fe,'M iso',coords) +%---------- +% Total number of nodes in each voxel The voxel2FN pairs are row size +% equals number of nodes and column size is always 2. The entries of +% the first column are the fiber number. The entries in the second +% column are the node of the fiber inside the voxel. +% val = feGet(fe,'n nodes'); +% val = feGet(fe,'n nodes',voxelsIndices); +% val = feGet(fe,'n nodes',coords); +%---------- +% Return the total number of fibers for all the voxels or in a set of +% voxels. +% nFibers = feGet(fe,'uniquefnum'); % all the voxels +% nFibers = feGet(fe,'uniquefnum',[1 2 3 4]); % for some the voxels, +% % specified by indexes +% nFibers = feGet(fe,'uniquefnum',coords); % for some the voxels, +% % specified by coordinates +%---------- +% Return the indexes of the fibers for all the voxels or in a set of +% voxels. +% idxFibers = feGet(fe,'uniquef'); % all the voxels +% idxFibers = feGet(fe,'uniquef',[1 2 3 4]); % for some the voxels, +% % specified by indexes +% idxFibers = feGet(fe,'uniquef',coords); % for some the voxels, +% % specified by coordinates +%---------- +% Return the total number of fibers for all the voxels or in a set of +% voxels +% nFibers = feGet(fe,'totfnum'); % all the voxels +% nFibers = feGet(fe,'totfnum',[1 2 3 4]); % for some the voxels, +% % specified by indexes +% nFibers = feGet(fe,'totfnum',coords); % for some the voxels, +% % specified by coordinates +%---------- +% Return the indexes of the fibers for all the voxels or in a set of +% voxels +% idxFibers = feGet(fe,'totf'); % all the voxels +% idxFibers = feGet(fe,'totf',[1 2 3 4]); % for some the voxels, +% % specified by indexes +% idxFibers = feGet(fe,'totfibers',coords); % for some the voxels, +% % specified by coordinates +%---------- +% Return the number of fibers in the model. +% nFibers = feGet(fe,'n fibers'); +%---------- +% Weights of the isotropic voxel signals, this is the mean signal in +% each voxel. +% val = feGet(fe,'iso weights'); +% val = feGet(fe,'iso weights'coords) +% val = feGet(fe,'iso weights',voxelIndices) +%---------- +% Weights of the fiber component. For all the fibers or a subset of +% them. +% w = feGet(fe,'fiber weights') +% w = feGet(fe,'fiber weights',fiberIndices) +%---------- +% Weights of the fiber component with a subset of the fibers' weights +% set to zero. This can be used to test the loss in RMSE for the +% connectome when a subset of fibers is removed, but the connectome is +% not fitted again. +% w = feGet(fe,'fiber weights test',fiberIndices) +%---------- +% Predicted signal (demeaned) with a subset of fibers' weights set to 0. +% This can be used to test the loss in RMSE for the connectome when a +% subset of fibers is removed, but the connectome is not fitted again. +% +% pSig = feGet(fe,'pSig fiber test',fiberIndices); +% pSig = feGet(fe,'pSig fiber test',fiberIndices,voxelIndices); +% pSig = feGet(fe,'pSig fiber test',fiberIndices,coords); +%---------- +% Measured signal in VOI, this is the raw signal. not demeaned +% +% dSig = feGet(fe,'dSig full') +%--------- +% Measured signal in VOI, demeaned, this is the signal used for the +% fiber-portion of the M model. +% +% dSig = feGet(fe,'dsigdemeaned'); +% dSig = feGet(fe,'dsigdemeaned',[1 10 100]); +% dSig = feGet(fe,'dsigdemeaned',coords); +%--------- +% Get the demeaned signal for a subset of rows. +% Useful for cross-validation. +% dSig = feGet(fe,'dsigrowssubset',voxelsList); +%--------- +% Predicted signal of fiber alone (demeaned). +% pSig = feGet(fe,'pSig fiber'); +% pSig = feGet(fe,'pSig fiber',coords); +% pSig = feGet(fe,'pSig fiber',voxelIndices); +%--------- +% Predicted measured signal from both fiber and iso +% pSig = feGet(fe,'pSig full') +% pSig = feGet(fe,'pSig full',coords) +% pSig = feGet(fe,'pSig full',voxelIndices) +%--------- +% The woxels returned by a fit of LiFE by voxel/fiber +% w = feGet(fe,'fiberweightsvoxelwise') +%--------- +% Predict the diffusion signal for the fiber component +% with the voxel-wise fit of LiFE +% pSig = feGet(fe,'psigfvoxelwise') +% pSig = feGet(fe,'psigfvoxelwise',coords) +% pSig = feGet(fe,'psigfvoxelwise',voxelIndices) +%--------- +% Predict the diffusion signal for the fiber component +% with the voxel-wise fit of LiFE, return the an array of pSigXnVoxel +% pSig = feGet(fe,'psigfvoxelwisebyvoxel') +% pSig = feGet(fe,'psigfvoxelwisebyvoxel',coords) +% pSig = feGet(fe,'psigfvoxelwisebyvoxel',voxelIndices) +%--------- +% The fiber and isotropic weights as a long vector +% w = feGet(fe,'fullweights') +%--------- +% Return the global R2 (fraction of variance explained) of the full life +% model. +% R2 = feGet(fe,'total r2'); +%--------- +% Percent variance explained +% R2 = feGet(fe,'explained variance') +%--------- +% Root mean squared error of the LiFE fit to the whole data +% rmse = feGet(fe,'rmse') +%--------- +% Residual signal: (fiber prediction - measured_demeaned). +% res = feGet(fe,'res sig fiber') +%--------- +% Residual signal: (full model prediction - measured signal). +% res = feGet(fe,'res sig full'); +%--------- +% Residual signal: (fiber model prediction - demeaned measured signal) +% with added mean signal. Res is returned as a vector. +% This is used to reconstruct an image (volume) to be used for the +% refinement process. +% res = feGet(fe,'fiber res sig with mean'); +% res = feGet(fe,'fiber res sig with mean',coords); +% res = feGet(fe,'fiber res sig with mean',voxelIndices); +%--------- +% Residual signal fiber model prediction - demeaned measured signal +% with added mean signal. Res is returned as an array (nBvecs x nVoxel). +% This is used to reconstruct an image (volume) to be used for the +% refinement process. +% res = feGet(fe,'fiber res sig with mean voxel'); +% res = feGet(fe,'fiber res sig with mean voxel',coords); +% res = feGet(fe,'fiber res sig with mean voxel',voxelIndices); +%--------- +% Predicted signal by the fiber model in a set of voxels. +% Vox subfield stores per voxel within the VOI. The pSig has size of the +% dwi. - It is stored as val = pSig(X,Y,Z,Theta) +% +% pSig = feGet(fe, 'pSig fiber by voxel'); +% pSig = feGet(fe, 'pSig fiber by voxel',coords); +% pSig = feGet(fe, 'pSig fiber by voxel',voxelIndex); +%--------- +% Return a column vector of the proportion of variance explained in +% each voxel. +% R2byVox = feGet(fe,'voxr2'); +% R2byVox = feGet(fe,'voxr2',coords); +%--------- +% Return a column vector of the proportion of variance explained in +% each voxel. (Normalized to the squared mean diffusion signal in each voxel) +% R2byVox = feGet(fe,'voxr2zero'); +% R2byVox = feGet(fe,'voxr2zero',coords); +%--------- +% Return the percent of varince explained in each voxel. +% R2byVox = feGet(fe,'var exp by voxel'); +% R2byVox = feGet(fe,'var exp by voxel',coords); +%--------- +% Demeaned diffusion signal in each voxel. +% dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel'); +% dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel',coords); +% dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel',vxIndex); +%--------- +% Full (measured) signal in each voxel. +% dSigByVoxel = feGet(fe,'dSig full by Voxel'); +% dSigByVoxel = feGet(fe,'dSig full by Voxel',coords); +% dSigByVoxel = feGet(fe,'dSig full by Voxel',vxIndex); +%--------- +% Predicted signal by the full model in a set of voxeles. +% pSigByVoxel = feGet(fe, 'pSig full by voxel'); +% pSigByVoxel = feGet(fe, 'pSig full by voxel',coords); +% pSigByVoxel = feGet(fe, 'pSig full by voxel',voxelIndex); +%--------- +% A volume of RMSE values. +% RMSE = feGet(fe,'vox rmse') +% RMSE = feGet(fe,'vox rmse',coords) +% RMSE = feGet(fe,'vox rmse',vxIndex) +%--------- +% A volume of RMSE values with a subset of fibers' weights set to 0. +% RMSE = feGet(fe,'vox rmse',fiberIndices) +% RMSE = feGet(fe,'vox rmse',fiberIndices,coords) +% RMSE = feGet(fe,'vox rmse',fiberIndices,voxelIndex) +%--------- +% Fibers' residual signal by voxel. +% res = feGet(fe,'res sig fiber vox') +% res = feGet(fe,'res sig fiber vox',coords) +% res = feGet(fe,'res sig fiber vox',vxIndex) +%--------- +% Full (measured) residual signal by voxel. +% res = feGet(fe,'res sig full vox') +% res = feGet(fe,'res sig full vox',coords) +% res = feGet(fe,'res sig full vox',vxIndex) +%--------- +% Fibers' residual signal by voxel with mean signal added (with added +% isotropic component). +% This is used to compute the residual signal for the refinement. +% res = feGet(fe,'fiber res sig with mean vox') +% res = feGet(fe,'fiber res sig with mean vox',coords) +% res = feGet(fe,'fiber res sig with mean vox',vxIndex) +%--------- +% Residual signal full model prediction from a multi-voxel fit. +% res = feGet(fe,'res sig full voxfit'); +% res = feGet(fe, 'res sig full voxfit',coords); +% res = feGet(fe, 'res sig full voxfit',voxelIndex); +%--------- +% Fiber density statistics. +% Computes the fiber density (how many fibers in each voxel) +% We compute the following values: +% (1) The number of fibers in each voxel +% (2) The number of unique fibers with non-zero weights +% (3) The sum of the weights in each voxel +% (4) The mean of the weights in each voxel +% (5) The variance of the weigths in each voxel +% pSig = feGet(fe,'fiberdensity'); +%--------- +% Given an VOI or a set of indices to voxels returns the indices of the matching voxels inside the big +% volume, which ordinarily represents the full connectome. +% voxelIndices = feGet(fe,'voxelsindices',coords) +% IMPORTANT: Size(coords) must be Nx3; +% voxelIndices = feGet(fe,'voxelsindices',voxelIndices) +% IMPORTANT: Indices MUST be a column vector for this +% code to work. Size(voxelIndices) = Nx1; +%--------- +% Given an VOI finds the indices of the matching voxels inside the big +% volume, which ordinarily represents the full connectome. +% +% foundVoxels = feGet(fe,'find voxels',coords) +% +% coords is a Nx3 set of coordinates in image space +% foundVoxels is a vector of 1's and 0's, there is a one for each +% location the the connectome coordinates for which there is a match in +% the coords +%--------- +% Given a set of VOI coords finds the row numbers of the Model matrix +% (or equivalently the dSig vector) that represent the data for this +% set of VOI coords. +% foundVoxels = feGet(fe,'coords 2 rows',coords) +% coords - a Nx3 set of coordinates in image space +% foundVoxels - a binary vector that is 1 for each Model matrix row +% that corresponds to at least one of the coords. +%--------- +% Quaternian transformation from IMAGE space to ACPC space. +% xform = feGet(fe,'xform') +%--------- +% Quaternian transformation from ACPC space to IMAGE space. +% xform = feGet(fe,'xform') +%--------- +% Dimensions of the DW volume. +% dim = feGet(fe,'dims') +%--------- +% Dimensions of the maps of parameters and results. +% dims = feGet(fe, 'mapsize') +%--------- +% Path to the 3D Anatomy Volume. +% anatomyfile = feGet(fe, 't1 file') +% +% End of feGet.m parameters, +% +% Copyright (2013-2014), Franco Pestilli, Stanford University, pestillifranco@gmail.com. + +val = []; + +% Format the input parameters. +param = lower(strrep(param,' ','')); + +% Start sorting the input and computing the output. +switch param + case 'name' + % Name of the current fe structure. + % + % name = feGet(fe,'name') + val = fe.name; + + case 'type' + % The type of objes (always, fascicle evaluation) + % + % type = feGet(fe,'type') + val = fe.type; % Always fascicle evaluation + + % Set top level structure, not just single slot + case 'life' + % Structure of parameters and results from LIFE analysis + % + % life = feGet(fe,'life') + val = fe.life; + + case {'fgimg','fibersimg'} + % Return the connectome (fiber group) in image coordinates. + % + % fg = feGet(fe,'fg img') + val = fe.fg; % Fiber group candidate fascicles, uses fgSet/Get + + case {'fgacpc','fibersacpc'} + % return the connectome in acpc coordinates. + % + % fg = feGet(fg,'fg acpc') + xform = feGet(fe,'img2acpcxform'); + val = dtiXformFiberCoords(feGet(fe,'fgimg'),xform,'acpc'); + + case 'roi' + % Return the VOI comprised by the full connectome. + % + % roi = feGet(fe,'roi') + val = fe.roi; + + case 'roiacpc' + % Return the VOI comprised by the full connectome. + % + % roi = feGet(fe,'roi acpc') + name = sprintf('roi_%s',fe.fg.name); + randColor = rand(1,3); + val = dtiNewRoi(name,randColor,fefgGet(feGet(fe,'fg acpc'),'unique image coords')); + + case 'xform' + % Transforms between coords for fg, roi, and dwi data + % + % xform = feGet(fe,'xform') + val = fe.life.xform; + + case 'dwi' + % Load the diffusion weighted data. + % + % dwi = feGet(fe,'dwi') + val = dwiLoad(feGet(fe,'dwifile')); + + case 'dwirepeat' + % Load the diffusion weighted data. + % + % dwi = feGet(fe,'dwirepeat') + val = dwiLoad(feGetRep(fe,'dwifile')); + + case 'dwifile' + % Load the diffusion weighted data. + % + % dwiFile = feGet(fe,'dwifile') + val = fe.path.dwifile; + + case 'dwifilerep' + % Load the diffusion weighted data. + % + % dwiFile = feGet(fe,'dwifilerep') + val = fe.path.dwifilerep; + + case 'savedir' + % Directory where the LiFe structes are saved by defualt. + % + % sdir = feGet(fe,'savedir'); + val = fe.path.savedir; + + case {'bvecs'} + % Diffusion directions. + % + % val = feGet(fe,'bvecs'); + val = fe.life.bvecs; + + case {'bvecsindices'} + % Indices to the diffusion directions in the DWi 4th Dimension. + % + % val = feGet(fe,'bvecs indices'); + val = fe.life.bvecsindices; + + case {'nbvecs','nbvals'} + % Number of B0's + % + % val = feGet(fe,'n bvals'); + val = length(feGet(fe,'bvals')); + + case {'bvals'} + % B0 Values. + % + % bval = feGet(fe,'bvals') + val = fe.life.bvals; + + case {'diffusionsignalinvoxel','dsiinvox','dsigvox','dsigmeasuredvoxel'} + % Returns a nVoxels X nBvecs array of measured diffusion signal + % + % val = feGet(fe,'dsiinvox'); + % val = feGet(fe,'dsiinvox',voxelsIndices); + % val = feGet(fe,'dsiinvox',coords); + val = fe.life.diffusion_signal_img(feGet(fe,'voxelsindices',varargin),:)'; + + case {'diffusionsignalinvoxeldemeaned','dsiinvoxdemeaned'} + % Returns a nVoxels X nBvecs array of demeaned diffusion signal + % + % val =feGet(fe,'dsiinvoxdemeaned'); + % val =feGet(fe,'dsiinvoxdemeaned',voxelsIndices); + % val =feGet(fe,'dsiinvoxdemeaned',coords); + nBvecs = feGet(fe,'nBvecs'); + voxelIndices = feGet(fe,'voxelsindices',varargin); + val = fe.life.diffusion_signal_img(voxelIndices,:) - repmat(mean(fe.life.diffusion_signal_img(voxelIndices,:), 2),1,nBvecs); + keyboard + % THis seems to be wrong + + case {'b0signalimage','b0vox'} + % Get the diffusion signal at 0 diffusion weighting (B0) for this voxel + % + % val = feGet(fe,'b0signalvoxel'); + % val = feGet(fe,'b0signalvoxel',voxelIndex); + % val = feGet(fe,'b0signalvoxel',coords); + val = fe.life.diffusion_S0_img(feGet(fe,'voxelsindices',varargin), :); + + case {'fiberssubset','fsub','subsetoffibers','fgsubset'} + % Return a subset of fibers from the conenctome. + % + % fg = feGet(fe,'fiberssubset',fiberList); + val = feGet(fe,'fg img'); + fiberList = varargin{1}; + fibers = cell(size(fiberList)); + for ff = 1:length(fiberList) + fibers{ff} = val.fibers{fiberList(ff)}; + if isfield(val,'pathwayInfo') + pathInfo(ff) = val.pathwayInfo(fiberList(ff)); + end + end + val.fibers = fibers; + if isfield(val,'pathwayInfo') + val.pathwayInfo = pathInfo; + end + val.name = sprintf('subsetFrom:%s',val.name); + + case {'roivoxels','roicoords'} + % Return the coordinates of the VOI comprised in the connectome. + % Always in image space. + % + % coords = feGet(fe,'roi coords') + val = fe.roi.coords; + + case {'roicoordssubset'} + % Return the coordinates of the VOI comprised in the connectome. + % Always in image space. + % + % coords = feGet(fe,'roi coords') + val = feGet(fe,'roi coords'); + val = val(varargin{1},:); + + case {'nroivoxels','nvoxels'} + % Number of voxels in the connectome/VOI. + % + % nVoxels = feGet(fe,'n voxels') + val = size(feGet(fe,'roivoxels'),1); + + case {'usedvoxels','indexesofusedvoxels'} + % Indexes of actually used voxels. + % + % These can be different than the number of voxels in the VOI in case some + % voxels have no fibers in them. + % + % TO BE DEPRECATED. + % + % indxUsedVx = feGet(fe,'index of used voxels') + val = find(feGet(fe,'nnodes')); + + case {'nusedvoxels','numberofusedvoxels'} + % Number of actually used voxels. + % + % This can be less than the number of voxels in the VOI in case some + % voxels have no fibers in them. + % + % TO BE DEPRECATED. + % + % nUsedVx = feGet(fe,'index of used voxels') + val = size(feGet(fe,'used voxels'),2); + + case {'startrow','first index into the dsig vector for a voxel'} + % Returns the first index to a voxel in the dSig vector. + % + % The dSig vector is 1:nBvecs*nVoxels. + % + % val = feGet(fe,'start rows') + val = (varargin{1}-1)*feGet(fe,'nBvecs') + 1; + + case {'voxelrows','all indexes into the dsig vector for a set of voxels'} + % Return the rows corresponding to a set of voxels. + % + % rows = feGet(fe,'voxel rows',idxVoxel) + n = feGet(fe,'n voxels'); + nBvecs = feGet(fe,'n bvecs'); + voxelsToKeep = zeros(n,1); voxelsToKeep(varargin{1}) = 1; + val = logical(kron(voxelsToKeep(:),ones(nBvecs,1))); + + case {'modeltensor'} + val = fe.life.modelTensor; + + case {'mfiber','m','model'} + % Return the model (M matrix), or a subset of it. + % + % Mfiber = feGet(fe,'M fiber'); + % Mfiber = feGet(fe,'model',voxelsIndices); + % Mfiber = feGet(fe,'model',coords); + + % idxVoxels is an integer list of the voxels to retain + % If idxVoxels is not included, return the whole matrix + % M contains only the rows for the specified voxels (all directions) + + val = fe.life.M; + +% if isempty(varargin) +% % Return the whole M matrix +% val = fe.life.Mfiber; +% else +% % Return only the rows for the specified voxels, including all +% % directions. +% % voxelIndices = feGet(fe,'voxelsindices',varargin); +% % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); +% % val = fe.life.Mfiber(voxelRowsToKeep,:); +% val = fe.life.Mfiber(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin)),:); +% end + +% case {'mfibervoxelsubset','indexedafiber','mfiberindexed'} +% % Return a subset of measurements from the fiber portion of M matrix +% % The rows of M are specified. Remember that the rows refer to a +% % combination of voxel and measurement direction and potentially in the +% % future a b-value. Hence, the rows are not specific to a voxel. +% % +% % Mfiber = feGet(fe,'mfiber subset',rowsToKeep); +% +% if isempty(varargin), error('Subset of rows must be specified'); end +% val = fe.life.Mfiber(varargin{1},:); +% +% case {'msubsetfibers','mfiberssubset','mkeepfibers'} +% % Returns the model (M) with only a subset of columns (fibers). +% % +% % fiberList is a vector of indexes, e.g, [1 10 100] +% % +% % M = feGet(fe,'mkeepfibers',fiberList) +% val = fe.life.Mfiber(:,varargin{1}); + +% case {'miso'} +% % Isotropic portion of M matrix +% % returns the matrix for the full model or for a subset of voxels +% % +% % Miso = feGet(fe,'M iso') +% % Miso = feGet(fe,'M iso',voxelsIndices) +% % Miso = feGet(fe,'M iso',coords) +% if isempty(varargin) +% % Return the whole M iso +% val = feBuildSparseBlockDiag(feGet(fe,'nBvecs'),feGet(fe,'nVoxels')); +% else +% val = feBuildSparseBlockDiag(feGet(fe,'nBvecs'),length(feGet(fe,'voxelsindices',varargin))); +% end + + case {'voxel2fnpair','voxel2fibernodepair','v2fnp'} + % Pairing of fibers and nodes in each voxel. + % + % v2fnp = feGet(fe,'v2fnp'); + if isempty(fe.life.voxel2FNpair) + fprintf('[%s] fe.life.voxel2FNpair is empty, can be computed as: \nfe = feSet(fe,''v2fnp'',feGet(fe,''fg img''),''v2fn'',feGet(fe,''roi coords'')',mfilename); + return + end + val = fe.life.voxel2FNpair; + + case {'tensors','fibers tensors'} + % Tensors computed for each node and fiber in a set of voxels. + % + % t = feGet(fe,'tensors') + % t = feGet(fe,'tensors',voxelsIndices); + % t = feGet(fe,'tensors',coords); + if isempty(varargin) + val = fe.life.fibers.tensors; + else + vv = feGet(fe,'voxelsindices',varargin); + val = cell(size(vv)); + for ff = 1:length(vv) + val{ff} = fe.life.fibers.tensors{vv(ff)}; + end + end + + case {'voxeltensors','voxtensors','voxq'} + % Get all the tensors in a signle voxel + % + % val = feGet(fe,'voxtensors',voxelIndex) + % val = feGet(fe,'voxtensors',coord) + + % Index for the voxel + vv = feGet(fe,'voxelsindices',varargin); + + % The indexes of the voxeles used, to build LiFE. + usedVoxels = feGet(fe,'usedVoxels'); + voxIndex = usedVoxels(vv); + nNodes = feGet(fe,'nNodes'); + + % Get the tensors for each node in each fiber going through this voxel: + val = zeros(nNodes(voxIndex), 9); % Allocate space for all the tensors (9 is for the 3 x 3 tensor components) + for ii = 1:nNodes(voxIndex) % Get the tensors + val(ii,:) = fe.life.fibers.tensors{fe.life.voxel2FNpair{voxIndex}(ii,1)} ... + (fe.life.voxel2FNpair{voxIndex}(ii,2),:); + end + + case {'nnodes','numofnodes'} + % Total number of nodes in each voxel The voxel2FN pairs are row size + % equals number of nodes and column size is always 2. The entries of + % the first column are the fiber number. The entries in the second + % column are the node of the fiber inside the voxel. + % + % val = feGet(fe,'n nodes'); + % val = feGet(fe,'n nodes',voxelsIndices); + % val = feGet(fe,'n nodes',coords); + if ~isempty(fe.life.voxel2FNpair) + [val, ~] = cellfun(@size,fe.life.voxel2FNpair); + val = val(feGet(fe,'voxelsindices',varargin)); + end + + case {'numberofuniquefibersbyvoxel','uniquefnum'} + % Return the total number of fibers for all the voxels or in a set of + % voxels + % + % nFibers = feGet(fe,'uniquefnum'); % all the voxels + % nFibers = feGet(fe,'uniquefnum',[1 2 3 4]); % for some the voxels, + % % specified by indexes + % nFibers = feGet(fe,'uniquefnum',coords); % for some the voxels, + % % specified by coordinates + val = fe.life.fibers.unique.num(feGet(fe,'voxelsindices',varargin)); + + case {'indextouniquefibersbyvoxel','uniquef'} + % Return the indexes of the fibers for all the voxels or in a set of + % voxels. + % + % idxFibers = feGet(fe,'uniquef'); % all the voxels + % idxFibers = feGet(fe,'uniquef',[1 2 3 4]); % for some the voxels, + % % specified by indexes + % idxFibers = feGet(fe,'uniquef',coords); % for some the voxels, + % % specified by coordinates + vxIndex = feGet(fe,'voxels indices',varargin); + val = cell(length(vxIndex),1); + for ii = 1:length(vxIndex) + val{ii} = fe.life.fibers.unique.index{vxIndex(ii)}; + end + + case {'numberoftotalfibersbyvoxels','totfnum'} + % Return the total number of fibers for all the voxels or in a set of + % voxels + % + % nFibers = feGet(fe,'totfnum'); % all the voxels + % nFibers = feGet(fe,'totfnum',[1 2 3 4]); % for some the voxels, + % % specified by indexes + % nFibers = feGet(fe,'totfnum',coords); % for some the voxels, + % % specified by coordinates + val = fe.life.fibers.total.num(feGet(fe,'voxels indices',varargin)); + + case {'indexoftotalfibersbuvoxel','totf'} + % Return the indexes of the fibers for all the voxels or in a set of + % voxels + % + % idxFibers = feGet(fe,'totf'); % all the voxels + % idxFibers = feGet(fe,'totf',[1 2 3 4]); % for some the voxels, + % % specified by indexes + % idxFibers = feGet(fe,'totfibers',coords); % for some the voxels, + % % specified by coordinates + vxIndex = feGet(fe,'voxels indices',varargin); + val = cell(length(vxIndex),1); + for ii = 1:length(vxIndex) + val{ii} = fe.life.fibers.total.index{vxIndex(ii)}; + end + + case {'nfibers'} + % Return the number of fibers in the model. + % + %val = size(fe.life.fibers,2); + val = size(fe.fg.fibers,1); + + case {'natoms'} + % Return the number of atoms in the dictionary + val = size(fe.life.M.DictSig,2); + + case {'orient'} + % Return the number of atoms in the dictionary + val = fe.life.M.orient; + + case {'isoweights','weightsiso','meanvoxelsignal'} + % Weights of the isotropic voxel signals, this is the mean signal in + % each voxel. + % + % val = feGet(fe,'iso weights'); + % val = feGet(fe,'iso weights'coords) + % val = feGet(fe,'iso weights',voxelIndices) + val = feGet(fe,'Miso') \ feGet(fe,'dsig full')'; + val = val(feGet(fe,'voxelsindices',varargin)); + + case {'voxisoweights','voxweightsiso','voxmeanvoxelsignal'} + % Weights of the isotropic voxel signals, this is the mean signal in + % each voxel. + % Organized nBvecs x nVoxels + % + % val = feGet(fe,'iso weights'); + % val = feGet(fe,'iso weights'coords) + % val = feGet(fe,'iso weights',voxelIndices) + val = feGet(fe,'Miso') \ feGet(fe,'dsig full')'; + val = repmat(val,1,feGet(fe,'nbvecs'))'; + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:,feGet(fe,'voxelsindices',varargin)); + end + + case {'dsigiso','isodsig'} + % mean signalin each voxel, returned for each diffusion direction: + % size(nBvecsxnVoxels, 1). + % + % val = feGet(fe,'iso disg'); + % val = feGet(fe,'iso disg',coords) + % val = feGet(fe,'iso dsig',voxelIndices) + val = feGet(fe,'iso weights'); + val = repmat(val,1,feGet(fe,'nbvecs'))'; + val = val(:); + + case {'fiberweights'} + % Weights of the fiber component. For all the fibers or a subset of + % them. + % + % w = feGet(fe,'fiber weights') + % w = feGet(fe,'fiber weights',fiberIndices) + + % If the model was not fit yet, fit it, install the fit and then return + % the weights. + if ~isfield(fe.life,'fit') + fprintf('[%s] fe.life.fit is empty, can be computed as: \nfeSet(fe,''fit'',feFitModel(feGet(fe,''Mfiber''), feGet(fe,''dsigdemeaned''),''sgdnn''))',mfilename); + return + end + + % Get the weights + if ~isempty(varargin) % subselect the weights for the requested fibers + val = fe.life.fit.weights(varargin{1}); + else % Return all of them + val = fe.life.fit.weights; + end + + case {'fiberweightstest'} + % Weights of the fiber component with a subset of the fibers' weigth + % set to zero. This can be used to test the loss in RMSE for the + % connectome when a subset of fibers is removed, but the connectome is + % not fitted again. + % + % w = feGet(fe,'fiber weights test',fiberIndices) + + % If the model was not fit yet, fit it, install the fit and then return + % the weights. + if ~isfield(fe.life,'fit') + fprintf('[%s] fe.life.fit is empty, can be computed as: \nfeSet(fe,''fit'',feFitModel(feGet(fe,''Mfiber''), feGet(fe,''dsigdemeaned''),''sgdnn''))',mfilename); + return + end + + % Get the weights + if ~isempty(varargin) % subselect the weights for the requested fibers + val = fe.life.fit.weights; + val(varargin{1}) = 0; + else % A set of fiber weights is required as input + error('[%s] Indices to a subset of fiber-weights must be passed in w = feGet(fe,''fiber weights test'',fiberIndices))',mfilename); + end + + case {'fiberweightstestvoxelwise'} + % Weights of the fiber component with a subset of the fibers' weigth + % set to zero. This can be used to test the loss in RMSE for the + % connectome when a subset of fibers is removed, but the connectome is + % not fitted again. + % + % w = feGet(fe,'fiber weights test voxel wise',fiberIndices) + + % If the model was not fit yet, fit it, install the fit and then return + % the weights. + if ~isfield(fe.life,'voxfit') + fprintf('[%s] fe.life.fit is empty, can be computed as: \nfeSet(fe,''fit'',feFitModel(feGet(fe,''Mfiber''), feGet(fe,''dsigdemeaned''),''sgdnn''))',mfilename); + return + end + + % Get the weights + if ~isempty(varargin) % subselect the weights for the requested fibers + val = fe.life.voxfit.weights; + val(:,varargin{1}) = 0; + else % A set of fiber weights is required as input + error('[%s] Indices to a subset of fiber-weights must be passed in\nw = feGet(fe,''fiber weights test voxel wise'',fiberIndices))',mfilename); + end + + case {'dsigmeasured','dsigfull'} + % Measured signal in VOI, this is the raw signal. not demeaned + % + % dSig = feGet(fe,'dSig full') + val = fe.life.dSig; + % Return a subset of voxels + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'diffusionsignaldemeaned','dsigdemeaned'} + % Measured signal in VOI, demeaned, this is the signal used for the + % fiber-portion of the M model. + % + % dSig = feGet(fe,'dsigdemeaned'); + % dSig = feGet(fe,'dsigdemeaned',[1 10 100]); + % dSig = feGet(fe,'dsigdemeaned',coords); + nVoxels = feGet(fe,'nVoxels'); + nBvecs = feGet(fe,'nBvecs'); + dSig = reshape(fe.life.diffusion_signal_img',[1,nVoxels*nBvecs]); + val = (dSig - reshape(repmat( ... + mean(reshape(dSig, nBvecs, nVoxels),1),... + nBvecs,1), size(dSig)))'; + % Return a subset of voxels + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'dsigrowssubset','diffusionsignaldemeanedinsubsetofrows'} + % Get the demeaned signal for a subset of rows. + % Useful for cross-validation. + % + % dSig = feGet(fe,'dsigrowssubset',voxelsList); + dSig = feGet(fe,'dsigdemeaned'); + for vv = 1:length(voxelsList) + val(feGet(fe,'voxel rows',vv)) = dSig(feGet(fe,'voxel rows',voxelList(vv))); + end + + case {'psigfiber', 'fiberpsig','fiberpredicted','dsigpredictedfiber'} + % Predicted signal of fiber alone (demeaned). + % + % pSig = feGet(fefeGet(fe,'fiber weights','pSig fiber'); + % pSig = feGet(fe,'pSig fiber',coords); + % pSig = feGet(fe,'pSig fiber',voxelIndices); + %val = feGet(fe,'Mfiber')*feGet(fe,'fiber weights'); + %val = M_times_w(feGet(fe,'Mfiber'),feGet(fe,'fiber weights')); + val = fe.life.M.Mmatrix*feGet(fe,'fiber weights'); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'uniquefibersindicesinroi'} + % Find the unique fibers indices in the FE roi. + % Thisis necessary sometimes after changing the number of voxels in an + % FE structure, as it is performed by feConnectomeReduceVoxels.m + % + % FibInRoi = feGet(fe,'uniquefibersinroi'); + + % Get all the unique fibers in each voxel + uniquefvx = fefgGet(feGet(fe,'fibers img'), ... + 'uniquefibersinvox', ... + feGet(fe,'roi coords')); + val = []; + for ivx = 1:length(uniquefvx) + val = [val; uniquefvx{ivx}]; + end + val = unique(val); + + case {'weightsinroi'} + % Find the weights of the fibers in a specified volume. + % + % We compute the following values: + % (1) The number of unique fibers in the volume + % (2) The weights for the fibers in the roi + % + % wFibInRoi = feGet(fe,'weightsinroi'); + + % Get all the unique fibers in each voxel + FibInRoi = feGet(fe,'uniquefibersindicesinroi'); + + % extract the fber weights obtained in a LiFE fit + w = feGet(fe,'fiber weights'); + + % Return only the ones for the fibers in this roi + val = w(unique( FibInRoi )); + + case {'fiberdensity'} + % Fiber density statistics. + % + % Computes the fiber density (how many fibers in each voxel) + % + % We compute the following values: + % (1) The number of fibers in each voxel + % (2) The number of unique fibers with non-zero weights + % (3) The sum of the weights in each voxel + % (4) The mean of the weights in each voxel + % (5) The variance of the weigths in each voxel + % + % pSig = feGet(fe,'fiberdensity'); + + % Get the unique fibers in each voxel + uniquefvx = fefgGet(feGet(fe,'fibers img'), ... + 'uniquefibersinvox', ... + feGet(fe,'roi coords')); + + % extract the fber weights obtained in a LiFE fit + w = feGet(fe,'fiber weights'); + + % Compute the fiber density in three wasy: + % (1) The number of fibers in each voxel + % (2) The number of unique fibers with non-zero weights + % (3) The sum of the weights in each voxel + % (4) The mean of the weights in each voxel + % (5) The variance of the weigths in each voxel + val = nan(length(uniquefvx),5); + for ivx = 1:length(uniquefvx) + + % Number of fibers in each voxel + val(ivx,1) = length(uniquefvx{ivx}); + + % Number of fibers in ech voxel with non-zero weight + val(ivx,2) = length(uniquefvx{ivx}(w(uniquefvx{ivx}) > 0)); + + % Sum of fiber weights in each voxel + val(ivx,3) = sum(w(uniquefvx{ivx})); + + % Mean of fiber weights in each voxel + val(ivx,4) = nanmedian(w(uniquefvx{ivx})); + + % Var of fibers in each voxel + val(ivx,5) = nanvar(w(uniquefvx{ivx})); + end + +% case {'psigfibertest'} +% % Predicted signal (demeaned) with a subset of fibers' weights set to 0. +% % This can be used to test the loss in RMSE for the connectome when a +% % subset of fibers is removed, but the connectome is not fitted again. +% % +% % pSig = feGet(fe,'pSig fiber test',fiberIndices); +% % pSig = feGet(fe,'pSig fiber test',fiberIndices,voxelIndices); +% % pSig = feGet(fe,'pSig fiber test',fiberIndices,coords); +% if ~isempty(varargin) +% val = feGet(fe,'Mfiber')*feGet(fe,'fiber weights test',varargin{1}); +% +% % Now select a subset of voxels if requested +% if (length(varargin) == 2) +% % voxelIndices = feGet(fe,'voxelsindices',varargin); +% % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); +% % val = val(voxelRowsToKeep,:); +% val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin{2}))); +% end +% else +% error('[%s] A set f fiber indiced must be passed in. pSig = feGet(fe,''pSig fiber test'',fiberIndices))',mfilename); +% end + +% case {'psigfibertestvoxelwise'} +% % Predicted signal (demeaned) with a subset of fibers' weights set to 0. +% % This can be used to test the loss in RMSE for the connectome when a +% % subset of fibers is removed, but the connectome is not fitted again. +% % +% % pSig = feGet(fe,'pSig fiber test voxel wise',fiberIndices); +% % pSig = feGet(fe,'pSig fiber test voxel wise',fiberIndices,voxelIndices); +% % pSig = feGet(fe,'pSig fiber test voxel wise',fiberIndices,coords); +% +% if ~isempty(varargin) +% nVoxels = feGet(fe,'nvoxels'); +% w = feGet(fe,'fiber weights test voxel wise',varargin{1}); % Weights with a subset set to 0 +% val = cell(nVoxels,1); +% for ivox = 1:nVoxels +% % Predict the signal. +% val{ivox} = feGet(fe,'Mfiber',ivox)*w(ivox,:)'; +% end +% +% feOpenLocalCluster +% % Reorganize the signal into a vector +% val = vertcat(val{:})'; +% +% % Now select a subset of voxels if requested +% if (length(varargin) == 2) +% % voxelIndices = feGet(fe,'voxelsindices',varargin); +% % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); +% % val = val(voxelRowsToKeep,:); +% val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin{2}))); +% end +% else +% error('[%s] A set f fiber indiced must be passed in. pSig = feGet(fe,''pSig fiber test'',fiberIndices))',mfilename); +% end +% +% case {'predictedsignalfull','psigfull'} +% % Predicted measured signal from both fiber and iso +% % +% % pSig = feGet(fe,'pSig full') +% % pSig = feGet(fe,'pSig full',coords) +% % pSig = feGet(fe,'pSig full',voxelIndices) +% val = [feGet(fe,'M fiber'), feGet(fe,'M iso')] * feGet(fe,'full weights'); +% if ~isempty(varargin) +% % voxelIndices = feGet(fe,'voxelsindices',varargin); +% % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); +% % val = val(voxelRowsToKeep,:); +% val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); +% end + + case {'fullweights'} + % The fiber and isotropic weights as a long vector + % + % w = feGet(fe,'fullweights') + val = [feGet(fe,'fiber weights'); feGet(fe,'iso weights')]; + + case {'fiberweightsvoxelwise'} + % The woxels returned by a fit of LiFE by voxel/fiber + % + % w = feGet(fe,'fiberweightsvoxelwise') + val = fe.life.voxfit.weights; + + case {'psigfvoxelwise'} + % Predict the diffusion signal for the fiber component + % with the voxel-wise fit of LiFE + % + % pSig = feGet(fe,'psigfvoxelwise') + % pSig = feGet(fe,'psigfvoxelwise',coords) + % pSig = feGet(fe,'psigfvoxelwise',voxelIndices) + + if ~isfield(fe.life,'voxfit'), + error('[%s] Cannot find voxel-wise fit.\nTo fit the model voxel-wise run:\nfe = feFitModelByVoxel(fe)\n',mfilename); + end + val = fe.life.voxfit.psig; + + % Get a subset of voxels. + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'psigfvoxelwisebyvoxel'} + % Predict the diffusion signal for the fiber component + % with the voxel-wise fit of LiFE, return the an array of pSigXnVoxel + % + % pSig = feGet(fe,'psigfvoxelwisebyvoxel') + % pSig = feGet(fe,'psigfvoxelwisebyvoxel',coords) + % pSig = feGet(fe,'psigfvoxelwisebyvoxel',voxelIndices) + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'psigfvoxelwise'), nBvecs, nVoxels); + + case {'totalr2'} + % Return the global R2 (fraction of variance explained) of the full life + % model. + % + % R2 = feGet(fe,'total r2'); + + % measured = feGet(fe,'dsigdemeaned'); + % predicted = feGet(fe,'fiber p sig'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGet(fe,'diffusion signal demeaned') - ... + feGet(fe,'fiber predicted')).^2 ) ./ ... + sum((feGet(fe,'diffusion signal demeaned') - ... + mean(feGet(fe,'diffusion signal demeaned'))).^2) )); + + case {'totalr2voxelwise'} + % Return the global R2 (fraction of variance explained) of the full life + % model from a voxel-wise fit. + % + % R2 = feGet(fe,'total r2 vocel wise'); + + % measured = feGet(fe,'dsigdemeaned'); + % predicted = feGet(fe,'p sig f voxel wise'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGet(fe,'diffusion signal demeaned') - ... + feGet(fe,'psigfvoxelwise')').^2 ) ./ ... + sum((feGet(fe,'diffusion signal demeaned') - ... + mean(feGet(fe,'diffusion signal demeaned'))).^2) )); + + case {'totpercentvarianceexplained','totpve'} + % Percent variance explained + % + % R2 = feGet(fe,'explained variance') + val = 100 * feGet(fe,'total r2'); + + case {'rmsetotal','totalrmse'} + % Root mean squared error of the LiFE fit to the whole data + % + % rmse = feGet(fe,'rmse') + val = sqrt(mean((feGet(fe,'diffusion signal demeaned') - ... + feGet(fe,'pSig fiber')).^2)); + + case {'totalrmsevoxelwise'} + % Root mean squared error of the LiFE fit to the whole data from a + % vocel-wise fit + % + % rmse = feGet(fe,'rmse') + val = sqrt(mean((feGet(fe,'diffusion signal demeaned') - ... + feGet(fe,'pSig f voxelwise')').^2)); + + case {'ressigfiber'} + % Residual signal fiber prediction - measured_demeaned. + % + % res = feGet(fe,'res sig fiber') + val = (feGet(fe,'dsigdemeaned') - feGet(fe,'psig fiber')); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'ressigfull'} + % Residual signal full model prediction - measured signal. + % + % res = feGet(fe,'res sig full'); + % res = feGet(fe, 'res sig full',coords); + % res = feGet(fe, 'res sig full',voxelIndex); + val = (feGet(fe,'dsig full') - feGet(fe,'psig full')'); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'ressigfullvoxelwise'} + % Residual signal full model prediction from a multi-voxel fit. + % + % res = feGet(fe,'res sig full voxfit'); + % res = feGet(fe, 'res sig full voxfit',coords); + % res = feGet(fe, 'res sig full voxfit',voxelIndex); + %tic,val = feGet(fe,'dsig demeaned') - feGet(fe,'psigfvoxelwise') + feGet(fe,'dsigiso');toc + val = feGet(fe,'dsig full') - feGet(fe,'psigfvoxelwise')'; + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'fiberressigwithmean'} + % Residual signal fiber model prediction - demeaned measured signal + % with added mean signal. VECTOR FORM. + % + % This is used to reconstruct an image (volume) to be used for the + % refinement process. + % + % res = feGet(fe,'fiber res sig with mean'); + + % predicted = feGet(fe,'psig fiber'); + % measured = feGet(fe,'dsigdemeaned'); + % val = (measured_full - predicted demeaned); + val = (feGet(fe,'dsig full')' - feGet(fe,'psig fiber')); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'predictedfibersignalvoxel','psigfvox'} + % Predicted signal by the fiber model in a set of voxels. + % + % Vox subfield stores per voxel within the VOI + % The pSig has size of the dwi. + % It is stored as val = pSig(X,Y,Z,Theta) + % + % pSig = feGet(fe, 'pSig fiber by voxel'); + % pSig = feGet(fe, 'pSig fiber by voxel',coords); + % pSig = feGet(fe, 'pSig fiber by voxel',voxelIndex); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetOLD(fe,'pSig fiber'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin)); + + case {'predictedfullsignalvoxel','psigfullvox'} + % Predicted signal by the full model in a set of voxeles. + % + % Vox subfield stores per voxel within the VOI + % The pSig has size of the dwi. + % It is stored as val = pSig(X,Y,Z,Theta) + % + % pSig = feGet(fe, 'pSig full by voxel'); + % pSig = feGet(fe, 'pSig full by voxel',coords); + % pSig = feGet(fe, 'pSig full by voxel',voxelIndex); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'pSig full'), nBvecs, nVoxels); + + case {'voxelr2','r2vox','voxr2','r2byvoxel'} + % Return a column vector of the proportion of variance explained in + % each voxel. + % + % R2byVox = feGet(fe,'voxr2'); + % R2byVox = feGet(fe,'voxr2',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + nBvecs = feGet(fe,'nBvecs'); + val = (1 - (sum((measured - predicted).^2 ) ./ ... + sum((measured - repmat(mean(measured), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zero','r2voxzero','voxr2zero','r2byvoxelzero'} + % Return a column vector of the proportion of variance explained in + % each voxel. (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGet(fe,'voxr2zero'); + % R2byVox = feGet(fe,'voxr2zero',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + val = (1 - (sum((measured - predicted).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelvarianceexplained','varexpvox','voxvarexp','varexpbyvoxel'} + % Return the percent of varince explained in each voxel. + % + % R2byVox = feGet(fe,'var exp by voxel'); + % R2byVox = feGet(fe,'var exp by voxel',coords); + val = 100.*feGet(fe,'voxr2'); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2voxelwise','r2voxvoxelwise','voxr2voxelwise'} + % Return a column vector of the proportion of variance explained in + % each voxel. + % + % R2byVox = feGet(fe,'voxr2voxelwise'); + % R2byVox = feGet(fe,'voxr2voxewise',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'psig f voxel wise by voxel'); + nBvecs = feGet(fe,'nBvecs'); + val = (1 - (sum((measured - predicted).^2 ) ./ ... + sum((measured - repmat(mean(measured), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zerovoxelwise','voxr2zerovoxelwise'} + % Return a column vector of the proportion of variance explained in + % each voxel. (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGet(fe,'voxr2zerovoxelwise'); + % R2byVox = feGet(fe,'voxr2zerovoxelwise',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'psig f voxel wise by voxel'); + val = (1 - (sum((measured - predicted).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelvarianceexplainedvoxelwise','varexpvoxvoxelwise'} + % Return the percent of varince explained in each voxel. + % + % R2byVox = feGet(fe,'var exp by voxel'); + % R2byVox = feGet(fe,'var exp by voxel',coords); + val = 100.*feGet(fe,'voxr2voxelwise'); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'dsigdemeanedbyvoxel','dsigdemeanedvox'} + % Demeaned diffusion signal in each voxel + % + % dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel'); + % dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel',coords); + % dSigByVoxel = feGet(fe,'dsigdemeaned by Voxel',vxIndex); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'dsigdemeaned'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin)); + + case {'dsigfullbyvoxel','dsigfullvox','voxdsigfull'} + % Full (measured) signal in each voxel + % + % dSigByVoxel = feGet(fe,'dSig full by Voxel'); + % dSigByVoxel = feGet(fe,'dSig full by Voxel',coords); + % dSigByVoxel = feGet(fe,'dSig full by Voxel',vxIndex); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'dSig full'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'voxelrmse','voxrmse'} + % A volume of RMSE values + % + % RMSE = feGet(fe,'vox rmse') + % RMSE = feGet(fe,'vox rmse',coords) + % RMSE = feGet(fe,'vox rmse',vxIndex) + measured = feGet(fe,'dsigdemeaned by voxel'); + predicted = feGetOLD(fe,'pSig f vox'); + val = sqrt(mean((measured - predicted).^2,1)); + val = val(feGet(fe,'voxelsindices',varargin)); + + case {'voxelrmsevoxelwise','voxrmsevoxelwise'} + % A volume of RMSE values optained with the voxel-wise (voxelwise) fit. + % + % RMSE = feGet(fe,'vox rmse voxelwise') + % RMSE = feGet(fe,'vox rmse voxelwise',coords) + % RMSE = feGet(fe,'vox rmse voxelwise',vxIndex) + measured = feGet(fe,'dsigdemeaned by voxel'); + predicted = feGet(fe,'pSig f voxel wise by voxel'); + + val = sqrt(mean((measured - predicted).^2,1)); + val = val(feGet(fe,'voxelsindices',varargin)); + + case {'voxelrmsetest','voxrmsetest'} + % A volume of RMSE values with a subset of fibers' weights set to 0. + % + % RMSE = feGet(fe,'vox rmse',fiberIndices) + % RMSE = feGet(fe,'vox rmse',fiberIndices,coords) + % RMSE = feGet(fe,'vox rmse',fiberIndices,voxelIndex) + measured = feGet(fe,'dsigdemeaned by voxel'); + % Reshape the predicted signal by voxles + predicted = reshape(feGet(fe,'pSig fiber test',varargin{1}), feGet(fe,'nBvecs'), feGet(fe,'nVoxels')); + val = sqrt(mean((measured - predicted).^2,1)); + + if length(varargin) == 2 + val = val(feGet(fe,'voxelsindices',varargin)); + end + + case {'residualsignalfibervoxel','resfibervox'} + % Fibers' residual signal by voxel + % + % res = feGet(fe,'res sig fiber vox') + % res = feGet(fe,'res sig fiber vox',coords) + % res = feGet(fe,'res sig fiber vox',vxIndex) + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'res sig fiber'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'residualsignalfullvoxel','resfullvox'} + % Full (measured) residual signal by voxel + % + % res = feGet(fe,'res sig full vox') + % res = feGet(fe,'res sig full vox',coords) + % res = feGet(fe,'res sig full vox',vxIndex) + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'res sig full'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'fiberressigwithmeanvoxel'} + % Residual signal fiber model prediction - demeaned measured signal + % with added mean signal. VOXEL FORM (nBvecs x nVoxel). + % + % This is used to reconstruct an image (volume) to be used for the + % refinement process. + % + % res = feGet(fe,'fiber res sig with mean'); + + % predicted = feGet(fe,'psig fiber'); + % measured = feGet(fe,'dsigdemeaned'); + % val = (measured - predicted) + (measured_full - measured); + val = feGet(fe,'fiberressigwithmean'); + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(val, nBvecs, nVoxels); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:, feGet(fe,'return voxel indices',varargin)); + end + + case {'fiberressigwithmeanvox','resfibermeanvox'} + % Fibers' residual signal by voxel with mean signal added (with added + % isotropic component). + % + % This is used to compute the residual signal for the refinement. + % + % res = feGet(fe,'fiber res sig with mean vox') + % res = feGet(fe,'fiber res sig with mean vox',coords) + % res = feGet(fe,'fiber res sig with mean vox',vxIndex) + nBvecs = feGet(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGet(fe,'fiber res sig with mean'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'voxelsindices','returnvoxelindices','voxelindexes''returnvoxelindexes'} + % Given an VOI or a set of indices to voxels returns the indices of the matching voxels inside the big + % volume, which ordinarily represents the full connectome. + % + % voxelIndices = feGet(fe,'voxelsindices',coords) + % voxelIndices = feGet(fe,'voxelsindices',voxelIndices) + % IMPORTANT: Indices MUST be a column vector for this + % code to work. + % + % coords is a Nx3 set of coordinates in image space + % voxelIndices is a vector of 1's and 0's, there is a one for each + % location the the connectome coordinates for which there is a match in + % the coords + % + varargin = varargin{1}; + if ( ~isempty(varargin) ) + if ( size(varargin{1},2) == 3 ) + % If a set of coordinates were passed in we return the indices. + val = logical(feGet(fe,'find voxels',varargin{1})); + else + % If indices were passed in, we sort and return them. + val = sort(varargin{1}); + end + else + % If no coordinates were passed at all, we return all the indices. + val = true(feGet(fe,'n voxels'),1); + end + + case {'findvoxels','findvoxelindexes','findvoxelsinconnectome','findvoxelsinconnectomeroi', ... + 'voxel2index','coords2index'} + % Given an VOI finds the indices of the matching voxels inside the big + % volume, which ordinarily represents the full connectome. + % + % foundVoxels = feGet(fe,'find voxels',coords) + % + % coords is a Nx3 set of coordinates in image space + % foundVoxels is a vector of 1's and 0's, there is a one for each + % location the the connectome coordinates for which there is a match in + % the coords + + % Compute the values for a subset of voxels + if isempty(varargin) + % If no coordinates were passed at all, we return all the indices. + val = ones(feGet(fe,'n voxels'),1); + else + % The stored coordinates are at a resolution of the image, typically + % 2mm isotropic. The VOI should also be in image resolution. + % ---- Franco: + % This is how I had it. I think it is worng: + % val = ismember(feGet(fe,'roi coords'), varargin{1}, 'rows'); % This is slow + % This is hwo I think it should be: + [~,val] = ismember(varargin{1}, feGet(fe,'roi coords'),'rows'); % This is slow + end + + case {'voxelcoords2voxelrows','coords2rows'} + % Given a set of VOI coords finds the row numbers of the Model matrix + % (or equivalently the dSig vector) that represent the data for this + % set of VOI coords. + % + % foundVoxels = feGet(fe,'coords 2 rows',coords) + % + % coords - a Nx3 set of coordinates in image space + % foundVoxels - a binary vector that is 1 for each Model matrix row + % that corresponds to at least one of the coords. + val = feGet(fe,'voxel rows',find(feGet(fe,'find voxels',varargin{1}))); + + % ------ Spatial coordinate transforms for voxels and fg to coordinate frames + case {'xformimg2acpc','xform2acpc','img2acpc','img2acpcxform'} + % Quaternian transformation from IMAGE space to ACPC space. + % + % xform = feGet(fe,'xform') + val = fe.life.xform.img2acpc; + case {'xformacpc2img','xform2img','acpc2img','acpc2imgxform'} + % Quaternian transformation from ACPC space to IMAGE space. + % + % xform = feGet(fe,'xform') + val = fe.life.xform.acpc2img; + case {'volumesize','dims','dim','imagedim'} + % Dimensions of the DW volume. + % + % dim = feGet(fe,'dims') + val = fe.life.imagedim; + case {'mapsize'} + % Dimensions of the maps of parameters and results. + % + % dims = feGet(fe, 'mapsize') + val = fe.life.imagedim(1:3); + + case {'anatomyfile'} + % Path to the 3D Anatomy Volume. + % anatomyfile = feGet(fe, 'anatomy file') + val = fe.path.anatomy; + case 'dtfile' + % Diffusion weighted file used for testing results + % dtfile = feGet(fe,'dtfile') + val = fe.path.dtfile; + case 'model' + % Multiway decomposition model elements + val = fe.life.M; + case 'lists' + % atoms, voxels and Nelem lists (to be revised for future elimination) + val.atoms = fe.life.fibers.atoms_list; + val.voxels = fe.life.fibers.voxels_list; + val.Nelem = fe.life.fibers.Nelem; + case 's0_img' + val = fe.life.diffusion_S0_img; + case 'nelem' + val = fe.life.fibers.Nelem; + case 'nphi' + val = fe.life.M.Nphi; + case 'ntheta' + val = fe.life.M.Ntheta; + + + otherwise + help('feGet') + fprintf('[feGet] Unknown parameter << %s >>...\n',param); + keyboard +end + +end % END MAIN FUNCTION diff --git a/fe/feGetRep.m b/fe/feGetRep.m new file mode 100755 index 0000000..0ec1b29 --- /dev/null +++ b/fe/feGetRep.m @@ -0,0 +1,873 @@ +function val = feGetRep(fe,param,varargin) +% Get function for fascicle evaluation structure, to use for a repeated +% measure calculation. +% +% This function is similar to feGet but uses the repeted dataset to compute +% the DWI signal and all the calculations that depend on the DWI signal +% will be different. +% +% Importantly, this function will use calls to feGet every time we compute +% values that depend on the LiFE model or fit. +% +% This function allows for computing measures of: +% (1) data reliability and +% (2) model versus data reliability +% +% val = feGetRep(fe,param,varargin) +% +% INPUTS: +% Coords - Nx3 set of coordinates in image space +% voxelIndices - Vector of 1's and 0's, there is a one for each +% location the the connectome coordinates for which there is +% a match in the coords +% +% +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com +% +%---------- List of arguments ---- +% Name of the current fe structure. +% name = feGetRep(fe,'name') +%---------- +% The type of objes (always, fascicle evaluation) +% type = feGetRep(fe,'type') +%---------- +% Load the repeated-measure diffusion weighted data. +% dwi = feGetRep(fe,'dwirepeat') +%---------- +% Load the repeated measure of the diffusion weighted data. +% dwiFile = feGetRep(fe,'dwirepeatfile') +%---------- +% Directory where the LiFe structes are saved by defualt. +% sdir = feGetRep(fe,'savedir'); +%---------- +% Diffusion directions. +% val = feGetRep(fe,'bvecs'); +%---------- +% Indices to the diffusion directions in the DWi 4th Dimension. +% val = feGetRep(fe,'bvecs indices'); +%---------- +% Number of B0's +% val = feGetRep(fe,'n bvals'); +%---------- +% B0 Values. +% bval = feGetRep(fe,'bvals') +%---------- +% Returns a nVoxels X nBvecs array of measured diffusion signal +% val = feGetRep(fe,'dsiinvox'); +% val = feGetRep(fe,'dsiinvox',voxelsIndices); +% val = feGetRep(fe,'dsiinvox',coords); +%---------- +% Returns a nVoxels X nBvecs array of demeaned diffusion signal +% val =feGetRep(fe,'dsiinvoxdemeaned'); +% val =feGetRep(fe,'dsiinvoxdemeaned',voxelsIndices); +% val =feGetRep(fe,'dsiinvoxdemeaned',coords); +%---------- +% Get the diffusion signal at 0 diffusion weighting (B0) for this voxel +% val = feGetRep(fe,'b0signalimage'); +% val = feGetRep(fe,'b0signalimage',voxelIndex); +% val = feGetRep(fe,'b0signalimage',coords); +%---------- +% Weights of the isotropic voxel signals, this is the mean signal in +% each voxel. +% val = feGetRep(fe,'iso weights'); +% val = feGetRep(fe,'iso weights'coords) +% val = feGetRep(fe,'iso weights',voxelIndices) +%---------- +% Measured signal in VOI, this is the raw signal. not demeaned +% +% dSig = feGetRep(fe,'dSig full') +%--------- +% Measured signal in VOI, demeaned, this is the signal used for the +% fiber-portion of the M model. +% +% dSig = feGetRep(fe,'dsigdemeaned'); +% dSig = feGetRep(fe,'dsigdemeaned',[1 10 100]); +% dSig = feGetRep(fe,'dsigdemeaned',coords); +%--------- +% Get the demeaned signal for a subset of rows. +% Useful for cross-validation. +% dSig = feGetRep(fe,'dsigrowssubset',voxelsList); +%--------- +% Return the global R2 (fraction of variance explained) of the full life +% model. +% R2 = feGetRep(fe,'total r2'); +%--------- +% Percent variance explained +% R2 = feGetRep(fe,'explained variance') +%--------- +% Root mean squared error of the LiFE fit to the whole data +% rmse = feGetRep(fe,'rmse') +%--------- +% Residual signal: (fiber prediction - measured_demeaned). +% res = feGetRep(fe,'res sig fiber') +%--------- +% Residual signal: (full model prediction - measured signal). +% res = feGetRep(fe,'res sig full'); +%--------- +% Residual signal: (fiber model prediction - demeaned measured signal) +% with added mean signal. Res is returned as a vector. +% This is used to reconstruct an image (volume) to be used for the +% refinement process. +% res = feGetRep(fe,'fiber res sig with mean'); +% res = feGetRep(fe,'fiber res sig with mean',coords); +% res = feGetRep(fe,'fiber res sig with mean',voxelIndices); +%--------- +% Residual signal fiber model prediction - demeaned measured signal +% with added mean signal. Res is returned as an array (nBvecs x nVoxel). +% This is used to reconstruct an image (volume) to be used for the +% refinement process. +% res = feGetRep(fe,'fiber res sig with mean voxel'); +% res = feGetRep(fe,'fiber res sig with mean voxel',coords); +% res = feGetRep(fe,'fiber res sig with mean voxel',voxelIndices); +%--------- +% Return a column vector of the proportion of variance explained in +% each voxel. +% R2byVox = feGetRep(fe,'voxr2'); +% R2byVox = feGetRep(fe,'voxr2',coords); +%--------- +% Return a column vector of the proportion of variance explained in +% each voxel. (Normalized to the squared mean diffusion signal in each voxel) +% R2byVox = feGetRep(fe,'voxr2zero'); +% R2byVox = feGetRep(fe,'voxr2zero',coords); +%--------- +% Return the percent of varince explained in each voxel. +% R2byVox = feGetRep(fe,'var exp by voxel'); +% R2byVox = feGetRep(fe,'var exp by voxel',coords); +%--------- +% Demeaned diffusion signal in each voxel. +% dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel'); +% dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel',coords); +% dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel',vxIndex); +%--------- +% Full (measured) signal in each voxel. +% dSigByVoxel = feGetRep(fe,'dSig full by Voxel'); +% dSigByVoxel = feGetRep(fe,'dSig full by Voxel',coords); +% dSigByVoxel = feGetRep(fe,'dSig full by Voxel',vxIndex); +%--------- +% Predicted signal by the full model in a set of voxeles. +% pSigByVoxel = feGetRep(fe, 'pSig full by voxel'); +% pSigByVoxel = feGetRep(fe, 'pSig full by voxel',coords); +% pSigByVoxel = feGetRep(fe, 'pSig full by voxel',voxelIndex); +%--------- +% A volume of RMSE values. +% RMSE = feGetRep(fe,'vox rmse') +% RMSE = feGetRep(fe,'vox rmse',coords) +% RMSE = feGetRep(fe,'vox rmse',vxIndex) +%--------- +% A volume of RMSE values with a subset of fibers' weights set to 0. +% RMSE = feGetRep(fe,'vox rmse',fiberIndices) +% RMSE = feGetRep(fe,'vox rmse',fiberIndices,coords) +% RMSE = feGetRep(fe,'vox rmse',fiberIndices,voxelIndex) +%--------- +% Fibers' residual signal by voxel. +% res = feGetRep(fe,'res sig fiber vox') +% res = feGetRep(fe,'res sig fiber vox',coords) +% res = feGetRep(fe,'res sig fiber vox',vxIndex) +%--------- +% Full (measured) residual signal by voxel. +% res = feGetRep(fe,'res sig full vox') +% res = feGetRep(fe,'res sig full vox',coords) +% res = feGetRep(fe,'res sig full vox',vxIndex) +%--------- +% Fibers' residual signal by voxel with mean signal added (with added +% isotropic component). +% This is used to compute the residual signal for the refinement. +% res = feGetRep(fe,'fiber res sig with mean vox') +% res = feGetRep(fe,'fiber res sig with mean vox',coords) +% res = feGetRep(fe,'fiber res sig with mean vox',vxIndex) +%--------- +% Residual signal full model prediction from a multi-voxel fit. +% res = feGetRep(fe,'res sig full voxfit'); +% res = feGetRep(fe, 'res sig full voxfit',coords); +% res = feGetRep(fe, 'res sig full voxfit',voxelIndex); +%--------- +% Dimensions of the DW volume. +% dim = feGetRep(fe,'dims') +%--------- +% Dimensions of the maps of parameters and results. +% dims = feGetRep(fe, 'mapsize') +% +% End of feGetRep.m parameters, +% +% +% Copyright (2013-2014), Franco Pestilli, Stanford University, pestillifranco@gmail.com. + +val = []; + +% Format the input parameters. +param = lower(strrep(param,' ','')); + +% Start sorting the input and computing the output. +switch param + case 'name' + % Name of the current fe structure. + % + % name = feGetRep(fe,'name') + val = fe.rep.name; + + case 'type' + % The type of objes (always, fascicle evaluation) + % + % type = feGetRep(fe,'type') + val = fe.rep.type; % Always fascicle evaluation + + case 'dwi' + % Load the diffusion weighted data. + % + % dwi = feGetRep(fe,'dwirepeat') + val = dwiLoad(feGetRep(fe,'dwifile')); + + case 'dwifile' + % Load the repeated measure of the diffusion weighted data. + % + % dwiFile = feGetRep(fe,'dwirepeatfile') + val = fe.path.dwifilerep; + + case {'bvecs'} + % Diffusion directions. + % + % val = feGetRep(fe,'bvecs'); + val = fe.rep.bvecs; + + case {'bvecsindices'} + % Indices to the diffusion directions in the DWi 4th Dimension. + % + % val = feGetRep(fe,'bvecs indices rep'); + val = fe.rep.bvecsindices; + + case {'nbvecs','nbvals'} + % Number of B0's + % + % val = feGetRep(fe,'n bvals'); + val = length(feGetRep(fe,'bvals')); + + case {'bvals'} + % B0 Values. + % + % bval = feGetRep(fe,'bvals') + val = fe.rep.bvals; + + case {'diffusionsignalinvoxel','dsiinvox','dsigvox','dsigmeasuredvoxel'} + % Returns a nVoxels X nBvecs array of measured diffusion signal + % + % val = feGetRep(fe,'dsiinvox'); + % val = feGetRep(fe,'dsiinvox',voxelsIndices); + % val = feGetRep(fe,'dsiinvox',coords); + val = fe.rep.diffusion_signal_img(feGet(fe,'voxelsindices',varargin),:)'; + + case {'diffusionsignalinvoxeldemeaned','dsiinvoxdemeaned'} + % Returns a nVoxels X nBvecs array of demeaned diffusion signal + % + % val =feGetRep(fe,'dsiinvoxdemeaned'); + % val =feGetRep(fe,'dsiinvoxdemeaned',voxelsIndices); + % val =feGetRep(fe,'dsiinvoxdemeaned',coords); + nBvecs = feGetRep(fe,'nBvecs'); + voxelIndices = feGet(fe,'voxelsindices',varargin); + val = fe.rep.diffusion_signal_img(voxelIndices,:) - repmat(mean(fe.rep.diffusion_signal_img(voxelIndices,:), 2),1,nBvecs); + keyboard % THis seems to be worng + + case {'b0signalimage','b0vox'} + % Get the diffusion signal at 0 diffusion weighting (B0) for this voxel + % + % val = feGetRep(fe,'b0signalimage'); + % val = feGetRep(fe,'b0signalimage',voxelIndex); + % val = feGetRep(fe,'b0signalimage',coords); + val = fe.rep.diffusion_S0_img(feGet(fe,'voxelsindices',varargin), :); + + case {'isoweights','weightsiso','meanvoxelsignal'} + % Weights of the isotropic voxel signals, this is the mean signal in + % each voxel. + % + % val = feGetRep(fe,'iso weights'); + % val = feGetRep(fe,'iso weights'coords) + % val = feGetRep(fe,'iso weights',voxelIndices) + val = feGet(fe,'Miso') \ feGetRep(fe,'dsig full')'; + val = val(feGet(fe,'voxelsindices',varargin)); + + case {'dsigiso','isodsig'} + % mean signalin each voxel, returned for each diffusion direction: + % size(nBvecsxnVoxels, 1). + % + % val = feGetRep(fe,'iso disg'); + % val = feGetRep(fe,'iso disg',coords) + % val = feGetRep(fe,'iso dsig',voxelIndices) + val = feGetRep(fe,'iso weights'); + val = repmat(val,1,feGetRep(fe,'nbvecs'))'; + val = val(:); + + case {'dsigmeasured','dsigfull'} + % Measured signal in VOI, this is the raw signal. not demeaned + % + % dSig = feGetRep(fe,'dSig full') + val = fe.rep.diffusion_signal_img'; + val = val(:)'; + + % Return a subset of voxels + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'diffusionsignaldemeaned','dsigdemeaned'} + % Measured signal in VOI, demeaned, this is the signal used for the + % fiber-portion of the M model. + % + % dSig = feGetRep(fe,'dsigdemeaned'); + % dSig = feGetRep(fe,'dsigdemeaned',[1 10 100]); + % dSig = feGetRep(fe,'dsigdemeaned',coords); + nVoxels = feGet(fe,'nVoxels'); + nBvecs = feGetRep(fe,'nBvecs'); + val = (feGetRep(fe,'dsig measured') - reshape(repmat( ... + mean(reshape(feGetRep(fe,'dsig measured'), nBvecs, nVoxels),1),... + nBvecs,1), size(feGetRep(fe,'dsig measured'))))'; + % Return a subset of voxels + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'dsigrowssubset','diffusionsignaldemeanedinsubsetofrows'} + % Get the demeaned signal for a subset of rows. + % Useful for cross-validation. + % + % dSig = feGetRep(fe,'dsigrowssubset',voxelsList); + dSig = feGetRep(fe,'dsigdemeaned'); + for vv = 1:length(voxelsList) + val(feGet(fe,'voxel rows',vv)) = dSig(feGet(fe,'voxel rows',voxelList(vv))); + end + + case {'totalr2'} + % Return the global R2 (fraction of variance explained) of the full life + % model. + % + % R2 = feGetRep(fe,'total r2'); + + % measured = feGetRep(fe,'dsigdemeaned'); + % predicted = feGetRep(fe,'fiber p sig'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGetRep(fe,'diffusion signal demeaned') - ... + feGet(fe,'pSig fiber')).^2 ) ./ ... + sum((feGetRep(fe,'diffusion signal demeaned') - ... + mean(feGetRep(fe,'diffusion signal demeaned'))).^2) )); + + case {'totalr2voxelwise'} + % Return the global R2 (fraction of variance explained) of the full life + % model from a voxel-wise fit + % + % R2 = feGetRep(fe,'total r2'); + + % measured = feGetRep(fe,'dsigdemeaned'); + % predicted = feGetRep(fe,'p sig f voxel wise'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGetRep(fe,'diffusion signal demeaned')' - ... + feGet(fe,'pSig f voxel wise')).^2 ) ./ ... + sum((feGetRep(fe,'diffusion signal demeaned') - ... + mean(feGetRep(fe,'diffusion signal demeaned'))).^2) )); + + case {'totpve'} + % Total percent variance explained by data1 on data2 + % + % R2 = feGetRep(fe,'tot pve data') + val = 100 * feGetRep(fe,'total r2'); + + case {'totalr2data'} + % Return the global R2 (fraction of variance explained) of the full life + % model in data set 2 by data set 1. + % + % R2 = feGetRep(fe,'total r2 data'); + + % measured = feGetRep(fe,'dsigdemeaned'); + % predicted = feGetRep(fe,'fiber p sig'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGetRep(fe,'diffusion signal demeaned') - ... + feGet(fe,'diffusion signal demeaned')).^2 ) ./ ... + sum((feGetRep(fe,'diffusion signal demeaned') - ... + mean(feGetRep(fe,'diffusion signal demeaned'))).^2) )); + + case {'totpvedata'} + % Total percent variance explained by data1 on data2 + % + % R2 = feGetRep(fe,'tot pve data') + val = 100 * feGetRep(fe,'total r2 data'); + + case {'totalrmsedata'} + % Global root mean squared error of data1 on data 2 + % + % rmse = feGetRep(fe,'rmse data') + val = sqrt(mean((feGetRep(fe,'diffusion signal demeaned') - ... + feGet(fe,'diffusion signal demeaned')).^2)); + + case {'totalrmseratio'} + % Global ratio of root mean squared error of Model/Data + % + % rmse = feGetRep(fe,'rmse data ratio') + val = feGetRep(fe,'total rmse') ./ feGetRep(fe,'total rmse data'); + + case {'totalrmseratiovoxelwise'} + % Global ratio of root mean squared error of Model/Data from a + % voxel-wise fit + % + % rmse = feGetRep(fe,'totalrmseratiovoxelwise') + val = feGetRep(fe,'total rmse voxelwise') ./ feGetRep(fe,'total rmse data'); + + case {'totalrmse','rmsetotal'} + % Root mean squared error of the LiFE fit to the whole data + % + % rmse = feGetRep(fe,'rmsetotal') + val = sqrt(mean((feGetRep(fe,'diffusion signal demeaned') - ... + feGet(fe,'psigfiber')).^2)); + + case {'totalrmsevoxelwise'} + % Root mean squared error of the LiFE fit to the whole data from a + % voxel-wise fit + % + % rmse = feGetRep(fe,'totalrmsevoxelwise') + val = sqrt(mean((feGetRep(fe,'diffusion signal demeaned')' - ... + feGet(fe,'psigfvoxelwise')).^2)); + + case {'ressigfiber'} + % Residual signal fiber prediction - measured_demeaned. + % + % res = feGetRep(fe,'res sig fiber') + val = (feGetRep(fe,'dsigdemeaned') - feGet(fe,'psig fiber')); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'ressigfull'} + % Residual signal full model prediction - measured signal. + % + % res = feGetRep(fe,'res sig full'); + % res = feGetRep(fe, 'res sig full',coords); + % res = feGetRep(fe, 'res sig full',voxelIndex); + val = (feGetRep(fe,'dsig full') - feGet(fe,'psig full')'); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'ressigfullvoxelwise'} + % Residual signal full model prediction from a multi-voxel fit. + % + % res = feGetRep(fe,'res sig full voxfit'); + % res = feGetRep(fe, 'res sig full voxfit',coords); + % res = feGetRep(fe, 'res sig full voxfit',voxelIndex); + %tic,val = feGetRep(fe,'dsig demeaned') - feGet(fe,'psigfvoxelwise') + feGetRep(fe,'dsigiso');toc + val = feGetRep(fe,'dsig full') - feGet(fe,'psigfvoxelwise'); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'voxressigfullvoxelwise'} + % Residual signal full model prediction from a multi-voxel fit. + % ORganized in nvecsxn + % + % res = feGetRep(fe,'voxressigfullvoxelwise'); + % res = feGetRep(fe, 'voxressigfullvoxelwise',coords); + % res = feGetRep(fe, 'voxressigfullvoxelwise',voxelIndex); + %tic,val = feGetRep(fe,'dsig demeaned') - feGet(fe,'psigfvoxelwise') + feGetRep(fe,'dsigiso');toc + val = reshape(feGetRep(fe,'ressigfullvoxelwise'),feGetRep(fe,'nbvecs'),feGet(fe,'nvoxels')); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:,feGet(fe,'voxelsindices',varargin)); + end + + case {'voxisoweights','voxweightsiso','voxmeanvoxelsignal'} + % Weights of the isotropic voxel signals, this is the mean signal in + % each voxel. + % Organized nBvecs x nVoxels + % + % val = feGet(fe,'voxiso weights'); + % val = feGet(fe,'voxiso weights'coords) + % val = feGet(fe,'voxiso weights',voxelIndices) + val = feGet(fe,'Miso') \ feGetRep(fe,'dsig full')'; + val = repmat(val,1,feGet(fe,'nbvecs'))'; + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:,feGet(fe,'voxelsindices',varargin)); + end + + case {'fiberressigwithmean'} + % Residual signal fiber model prediction - demeaned measured signal + % with added mean signal. VECTOR FORM. + % + % This is used to reconstruct an image (volume) to be used for the + % refinement process. + % + % res = feGetRep(fe,'fiber res sig with mean'); + + % predicted = feGet(fe,'psig fiber'); + % measured = feGetRep(fe,'dsigdemeaned'); + % val = (measured_full - predicted demeaned); + val = (feGetRep(fe,'dsig full')' - feGet(fe,'psig fiber')); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'predictedfullsignalvoxel','psigfullvox'} + % Predicted signal by the full model in a set of voxeles. + % + % Vox subfield stores per voxel within the VOI + % The pSig has size of the dwi. + % It is stored as val = pSig(X,Y,Z,Theta) + % + % pSig = feGetRep(fe, 'pSig full by voxel'); + % pSig = feGetRep(fe, 'pSig full by voxel',coords); + % pSig = feGetRep(fe, 'pSig full by voxel',voxelIndex); + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'pSig full'), nBvecs, nVoxels); + + case {'voxelr2','r2vox','voxr2','r2byvoxel'} + % Return a column vector of the proportion of variance explained in + % each voxel. + % + % R2byVox = feGetRep(fe,'voxr2'); + % R2byVox = feGetRep(fe,'voxr2',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + nBvecs = feGetRep(fe,'nBvecs'); + val = (1 - (sum((measured - predicted).^2 ) ./ ... + sum((measured - repmat(mean(measured), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelss','ssvox','voxss','sumofsquaresbyvoxel'} + % Return a column vector of sum of squares error of the model + % prediction in each voxel + % + % ssem = feGetRep(fe,'voxss'); + % ssem = feGetRep(fe,'voxss',coords); + predicted = feGet(fe,'pSig f vox'); + measured = feGetRep(fe,'dSig demeaned by voxel'); + val = sum((measured - predicted).^2 ); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelssdata','ssvoxdata','voxssdata','sumofsquaresbyvoxeldata'} + % Return a column vector of sum of squares error of the data in + % each voxel + % + % ssed = feGetRep(fe,'voxssedata'); + % ssed = feGetRep(fe,'voxssdata',coords); + measured1 = feGet(fe,'dSig demeaned by voxel'); + measured2 = feGetRep(fe,'dSig demeaned by voxel'); + val = sum((measured2 - measured1).^2 ); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2data','r2voxdata','voxr2data','r2byvoxeldata'} + % Return a column vector of the proportion of variance explained in + % each voxel in data set 2 given the data in dataset 1. + % + % R2byVox = feGetRep(fe,'voxr2data'); + % R2byVox = feGetRep(fe,'voxr2data',coords); + measured1 = feGet(fe,'dSig demeaned by voxel'); + measured2 = feGetRep(fe,'dSig demeaned by voxel'); + nBvecs = feGetRep(fe,'nBvecs'); + val = (1 - (sum((measured2 - measured1).^2 ) ./ ... + sum((measured2 - repmat(mean(measured2), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zero','r2voxzero','voxr2zero','r2byvoxelzero'} + % Return a column vector of the proportion of variance explained in + % each voxel. (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGetRep(fe,'voxr2zero'); + % R2byVox = feGetRep(fe,'voxr2zero',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + val = (1 - (sum((measured - predicted).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2pearson','r2voxpearson','voxr2corr','r2byvoxelpearson'} + % Return a column vector of the squre of the pearson correlation coefficient + % + % R2byVox = feGetRep(fe,'voxr2corr'); + % R2byVox = feGetRep(fe,'voxr2corr',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + val = corrcoef(measured - predicted).^2; + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zerodata','r2voxzerodata','voxr2zerodata','r2byvoxelzerodata'} + % Return a column vector of the proportion of variance explained in + % each voxel in dataset 1 given the data in data set 2. + % (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGetRep(fe,'voxr2zerodata'); + % R2byVox = feGetRep(fe,'voxr2zerodata',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + measured2 = feGetRep(fe,'dSig demeaned by voxel'); + val = (1 - (sum((measured - measured2).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + + case {'voxelr2voxelwise','r2voxvoxelwise','voxr2voxelwise','r2voxelwisebyvoxel'} + % Return a column vector of the proportion of variance explained in + % each voxel. + % + % R2byVox = feGetRep(fe,'voxr2voxelwise'); + % R2byVox = feGetRep(fe,'voxr2voxelwise',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f voxel wise by voxel'); + nBvecs = feGetRep(fe,'nBvecs'); + val = (1 - (sum((measured - predicted).^2 ) ./ ... + sum((measured - repmat(mean(measured), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zerovoxelwise','r2zerovoxelwisebyvoxel','voxr2zerovoxelwise'} + % Return a column vector of the proportion of variance explained in + % each voxel. (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGetRep(fe,'voxr2zerovoxelwise'); + % R2byVox = feGetRep(fe,'voxr2zerovoxelwise',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f voxel wise by voxel'); + val = (1 - (sum((measured - predicted).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelvarianceexplained','varexpvox','voxvarexp','varexpbyvoxel'} + % Return the percent of varince explained in each voxel. + % + % R2byVox = feGetRep(fe,'var exp by voxel'); + % R2byVox = feGetRep(fe,'var exp by voxel',coords); + val = 100.*feGetRep(fe,'voxr2'); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelvarianceexplaineddata','varexpvoxdata','voxvarexpdata','varexpbyvoxeldata'} + % Return the percent of variance explained in each voxel in data set 1 + % given the data in data set 2. + % + % R2byVox = feGetRep(fe,'var exp by voxel data'); + % R2byVox = feGetRep(fe,'var exp by voxel data',coords); + val = 100.*feGetRep(fe,'voxr2 data'); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'dsigdemeanedbyvoxel','dsigdemeanedvox'} + % Demeaned diffusion signal in each voxel + % + % dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel'); + % dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel',coords); + % dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel',vxIndex); + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'dsigdemeaned'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin)); + + case {'dsigfullbyvoxel','dsigfullvox'} + % Full (measured) signal in each voxel + % + % dSigByVoxel = feGetRep(fe,'dSig full by Voxel'); + % dSigByVoxel = feGetRep(fe,'dSig full by Voxel',coords); + % dSigByVoxel = feGetRep(fe,'dSig full by Voxel',vxIndex); + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'dSig full'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'voxelrmse','voxrmse'} + % A volume of RMSE values + % + % RMSE = feGetRep(fe,'vox rmse') + % RMSE = feGetRep(fe,'vox rmse',coords) + % RMSE = feGetRep(fe,'vox rmse',vxIndex) + measured = feGetRep(fe,'dsigdemeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + val = sqrt(mean((measured - predicted).^2,1)); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelrmsevoxelwise','voxrmsevoxelwise'} + % A volume of RMSE values optained with the voxel-wise (vw) fit. + % + % RMSE = feGetRep(fe,'vox rmse vw') + % RMSE = feGetRep(fe,'vox rmse vw',coords) + % RMSE = feGetRep(fe,'vox rmse vw',vxIndex) + measured = feGetRep(fe,'dsigdemeaned by voxel'); + predicted = feGet(fe,'pSig f voxel wise by voxel'); + val = sqrt(mean((measured - predicted).^2,1)); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelrmseratio','voxrmseratio'} + % A volume with the ratio of the RMSE of model/data + % + % rmseRatio = feGetRep(fe,'vox rmse ratio') + % rmseRatio = feGetRep(fe,'vox rmse ratio',coords) + % rmseRatio = feGetRep(fe,'vox rmse ratio',vxIndex) + rmseData = feGetRep(fe,'vox rmse data'); + rmseModel = feGetRep(fe,'vox rmse'); + val = rmseModel ./ rmseData; + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'prmseratio','proportionrmseratio'} + % The probability of a ratio-value in the volume. + % Default across 25 log-distributed bins between [.5,2] + % + % rmseRatio = feGetRep(fe,'p rmse ratio') + % + % % Change the bins over whih the proportions are computed: + % bins = logspace(log10(.25),log10(4),50) + % rmseRatio = feGetRep(fe,'p rmse ratio',bins) + if isempty(varargin) + bins = logspace(log10(.5),log10(2),25); + end + % Extract the rmse ratio in each voxel + Rrmse = feGetRep(fe,'vox rmse ratio'); + % Compute the number of occurrences for a range of values. + [val(1,:),val(2,:)] = hist(Rrmse,bins); + val(1,:) = val(1,:)./sum(val(1,:)); + + case {'voxelrmseratiovoxelwise','voxrmseratiovoxelwise'} + % A volume with the ratio of the RMSE of model/data + % + % rmseRatio = feGetRep(fe,'vox rmse ratio voxel wise') + % rmseRatio = feGetRep(fe,'vox rmse ratio voxel wise',coords) + % rmseRatio = feGetRep(fe,'vox rmse ratio voxel wise',vxIndex) + rmseData = feGetRep(fe,'vox rmse data'); + rmseModel = feGetRep(fe,'vox rmse voxel wise'); + val = rmseModel ./ rmseData; + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelrmsedata','voxrmsedata'} + % A volume of RMSE values from data set 1 to data set 2 + % + % RMSE = feGetRep(fe,'vox rmse data') + % RMSE = feGetRep(fe,'vox rmse data',coords) + % RMSE = feGetRep(fe,'vox rmse data',vxIndex) + measured = feGet(fe,'dsigdemeaned by voxel'); + measured2 = feGetRep(fe,'dsigdemeaned by voxel'); + val = sqrt(mean((measured - measured2).^2,1)); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelrmsetest','voxrmsetest'} + % A volume of RMSE values with a subset of fibers' weights set to 0. + % + % RMSE = feGetRep(fe,'vox rmse',fiberIndices) + % RMSE = feGetRep(fe,'vox rmse',fiberIndices,coords) + % RMSE = feGetRep(fe,'vox rmse',fiberIndices,voxelIndex) + measured = feGetRep(fe,'dsigdemeaned by voxel'); + % Reshape the predicted signal by voxles + predicted = reshape(feGet(fe,'pSig fiber test voxel wise',varargin{1}), feGetRep(fe,'nBvecs'), feGet(fe,'nVoxels')); + val = sqrt(mean((measured - predicted).^2,1)); + + if length(varargin) == 2 + val = val(feGet(fe,'return voxel indices',varargin)); + end + + case {'voxelrmsetestvoxelwise','voxrmsetestvoxelwise'} + % A volume of RMSE values with a subset of fibers' weights set to 0. + % + % RMSE = feGetRep(fe,'voxel rmse test voxel wise',fiberIndices) + % RMSE = feGetRep(fe,'voxel rmse test voxel wise',fiberIndices,coords) + % RMSE = feGetRep(fe,'voxel rmse test voxel wise',fiberIndices,voxelIndex) + measured = feGetRep(fe,'dsigdemeaned by voxel'); + % Reshape the predicted signal by voxles + predicted = reshape(feGet(fe,'pSig fiber test voxel wise',varargin{1}), feGetRep(fe,'nBvecs'), feGet(fe,'nVoxels')); + val = sqrt(mean((measured - predicted).^2,1)); + + if length(varargin) == 2 + val = val(feGet(fe,'return voxel indices',varargin)); + end + + case {'residualsignalfibervoxel','resfibervox'} + % Fibers' residual signal by voxel + % + % res = feGetRep(fe,'res sig fiber vox') + % res = feGetRep(fe,'res sig fiber vox',coords) + % res = feGetRep(fe,'res sig fiber vox',vxIndex) + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'res sig fiber'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'residualsignalfullvoxel','resfullvox'} + % Full (measured) residual signal by voxel + % + % res = feGetRep(fe,'res sig full vox') + % res = feGetRep(fe,'res sig full vox',coords) + % res = feGetRep(fe,'res sig full vox',vxIndex) + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'res sig full'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'fiberressigwithmeanvoxel'} + % Residual signal fiber model prediction - demeaned measured signal + % with added mean signal. VOXEL FORM (nBvecs x nVoxel). + % + % This is used to reconstruct an image (volume) to be used for the + % refinement process. + % + % res = feGetRep(fe,'fiber res sig with mean'); + + % predicted = feGet(fe,'psig fiber'); + % measured = feGetRep(fe,'dsigdemeaned'); + % val = (measured - predicted) + (measured_full - measured); + val = feGetRep(fe,'fiberressigwithmean'); + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(val, nBvecs, nVoxels); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:, feGet(fe,'return voxel indices',varargin)); + end + + case {'fiberressigwithmeanvox','resfibermeanvox'} + % Fibers' residual signal by voxel with mean signal added (with added + % isotropic component). + % + % This is used to compute the residual signal for the refinement. + % + % res = feGetRep(fe,'fiber res sig with mean vox') + % res = feGetRep(fe,'fiber res sig with mean vox',coords) + % res = feGetRep(fe,'fiber res sig with mean vox',vxIndex) + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'fiber res sig with mean'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'volumesize','dims','dim','imagedim'} + % Dimensions of the DW volume. + % + % dim = feGetRep(fe,'dims') + val = fe.rep.imagedim; + case {'mapsize'} + % Dimensions of the maps of parameters and results. + % + % dims = feGetRep(fe, 'mapsize') + val = fe.rep.imagedim(1:3); + + otherwise + help('feGetRep') + fprintf('[feGetRep] Unknown parameter << %s >>...\n',param); + keyboard +end + +end % END MAIN FUNCTION diff --git a/fe/feGetRepOLD.m b/fe/feGetRepOLD.m new file mode 100755 index 0000000..78cfcdb --- /dev/null +++ b/fe/feGetRepOLD.m @@ -0,0 +1,873 @@ +function val = feGetRepOLD(fe,param,varargin) +% Get function for fascicle evaluation structure, to use for a repeated +% measure calculation. +% +% This function is similar to feGet but uses the repeted dataset to compute +% the DWI signal and all the calculations that depend on the DWI signal +% will be different. +% +% Importantly, this function will use calls to feGet every time we compute +% values that depend on the LiFE model or fit. +% +% This function allows for computing measures of: +% (1) data reliability and +% (2) model versus data reliability +% +% val = feGetRep(fe,param,varargin) +% +% INPUTS: +% Coords - Nx3 set of coordinates in image space +% voxelIndices - Vector of 1's and 0's, there is a one for each +% location the the connectome coordinates for which there is +% a match in the coords +% +% +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com +% +%---------- List of arguments ---- +% Name of the current fe structure. +% name = feGetRep(fe,'name') +%---------- +% The type of objes (always, fascicle evaluation) +% type = feGetRep(fe,'type') +%---------- +% Load the repeated-measure diffusion weighted data. +% dwi = feGetRep(fe,'dwirepeat') +%---------- +% Load the repeated measure of the diffusion weighted data. +% dwiFile = feGetRep(fe,'dwirepeatfile') +%---------- +% Directory where the LiFe structes are saved by defualt. +% sdir = feGetRep(fe,'savedir'); +%---------- +% Diffusion directions. +% val = feGetRep(fe,'bvecs'); +%---------- +% Indices to the diffusion directions in the DWi 4th Dimension. +% val = feGetRep(fe,'bvecs indices'); +%---------- +% Number of B0's +% val = feGetRep(fe,'n bvals'); +%---------- +% B0 Values. +% bval = feGetRep(fe,'bvals') +%---------- +% Returns a nVoxels X nBvecs array of measured diffusion signal +% val = feGetRep(fe,'dsiinvox'); +% val = feGetRep(fe,'dsiinvox',voxelsIndices); +% val = feGetRep(fe,'dsiinvox',coords); +%---------- +% Returns a nVoxels X nBvecs array of demeaned diffusion signal +% val =feGetRep(fe,'dsiinvoxdemeaned'); +% val =feGetRep(fe,'dsiinvoxdemeaned',voxelsIndices); +% val =feGetRep(fe,'dsiinvoxdemeaned',coords); +%---------- +% Get the diffusion signal at 0 diffusion weighting (B0) for this voxel +% val = feGetRep(fe,'b0signalimage'); +% val = feGetRep(fe,'b0signalimage',voxelIndex); +% val = feGetRep(fe,'b0signalimage',coords); +%---------- +% Weights of the isotropic voxel signals, this is the mean signal in +% each voxel. +% val = feGetRep(fe,'iso weights'); +% val = feGetRep(fe,'iso weights'coords) +% val = feGetRep(fe,'iso weights',voxelIndices) +%---------- +% Measured signal in VOI, this is the raw signal. not demeaned +% +% dSig = feGetRep(fe,'dSig full') +%--------- +% Measured signal in VOI, demeaned, this is the signal used for the +% fiber-portion of the M model. +% +% dSig = feGetRep(fe,'dsigdemeaned'); +% dSig = feGetRep(fe,'dsigdemeaned',[1 10 100]); +% dSig = feGetRep(fe,'dsigdemeaned',coords); +%--------- +% Get the demeaned signal for a subset of rows. +% Useful for cross-validation. +% dSig = feGetRep(fe,'dsigrowssubset',voxelsList); +%--------- +% Return the global R2 (fraction of variance explained) of the full life +% model. +% R2 = feGetRep(fe,'total r2'); +%--------- +% Percent variance explained +% R2 = feGetRep(fe,'explained variance') +%--------- +% Root mean squared error of the LiFE fit to the whole data +% rmse = feGetRep(fe,'rmse') +%--------- +% Residual signal: (fiber prediction - measured_demeaned). +% res = feGetRep(fe,'res sig fiber') +%--------- +% Residual signal: (full model prediction - measured signal). +% res = feGetRep(fe,'res sig full'); +%--------- +% Residual signal: (fiber model prediction - demeaned measured signal) +% with added mean signal. Res is returned as a vector. +% This is used to reconstruct an image (volume) to be used for the +% refinement process. +% res = feGetRep(fe,'fiber res sig with mean'); +% res = feGetRep(fe,'fiber res sig with mean',coords); +% res = feGetRep(fe,'fiber res sig with mean',voxelIndices); +%--------- +% Residual signal fiber model prediction - demeaned measured signal +% with added mean signal. Res is returned as an array (nBvecs x nVoxel). +% This is used to reconstruct an image (volume) to be used for the +% refinement process. +% res = feGetRep(fe,'fiber res sig with mean voxel'); +% res = feGetRep(fe,'fiber res sig with mean voxel',coords); +% res = feGetRep(fe,'fiber res sig with mean voxel',voxelIndices); +%--------- +% Return a column vector of the proportion of variance explained in +% each voxel. +% R2byVox = feGetRep(fe,'voxr2'); +% R2byVox = feGetRep(fe,'voxr2',coords); +%--------- +% Return a column vector of the proportion of variance explained in +% each voxel. (Normalized to the squared mean diffusion signal in each voxel) +% R2byVox = feGetRep(fe,'voxr2zero'); +% R2byVox = feGetRep(fe,'voxr2zero',coords); +%--------- +% Return the percent of varince explained in each voxel. +% R2byVox = feGetRep(fe,'var exp by voxel'); +% R2byVox = feGetRep(fe,'var exp by voxel',coords); +%--------- +% Demeaned diffusion signal in each voxel. +% dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel'); +% dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel',coords); +% dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel',vxIndex); +%--------- +% Full (measured) signal in each voxel. +% dSigByVoxel = feGetRep(fe,'dSig full by Voxel'); +% dSigByVoxel = feGetRep(fe,'dSig full by Voxel',coords); +% dSigByVoxel = feGetRep(fe,'dSig full by Voxel',vxIndex); +%--------- +% Predicted signal by the full model in a set of voxeles. +% pSigByVoxel = feGetRep(fe, 'pSig full by voxel'); +% pSigByVoxel = feGetRep(fe, 'pSig full by voxel',coords); +% pSigByVoxel = feGetRep(fe, 'pSig full by voxel',voxelIndex); +%--------- +% A volume of RMSE values. +% RMSE = feGetRep(fe,'vox rmse') +% RMSE = feGetRep(fe,'vox rmse',coords) +% RMSE = feGetRep(fe,'vox rmse',vxIndex) +%--------- +% A volume of RMSE values with a subset of fibers' weights set to 0. +% RMSE = feGetRep(fe,'vox rmse',fiberIndices) +% RMSE = feGetRep(fe,'vox rmse',fiberIndices,coords) +% RMSE = feGetRep(fe,'vox rmse',fiberIndices,voxelIndex) +%--------- +% Fibers' residual signal by voxel. +% res = feGetRep(fe,'res sig fiber vox') +% res = feGetRep(fe,'res sig fiber vox',coords) +% res = feGetRep(fe,'res sig fiber vox',vxIndex) +%--------- +% Full (measured) residual signal by voxel. +% res = feGetRep(fe,'res sig full vox') +% res = feGetRep(fe,'res sig full vox',coords) +% res = feGetRep(fe,'res sig full vox',vxIndex) +%--------- +% Fibers' residual signal by voxel with mean signal added (with added +% isotropic component). +% This is used to compute the residual signal for the refinement. +% res = feGetRep(fe,'fiber res sig with mean vox') +% res = feGetRep(fe,'fiber res sig with mean vox',coords) +% res = feGetRep(fe,'fiber res sig with mean vox',vxIndex) +%--------- +% Residual signal full model prediction from a multi-voxel fit. +% res = feGetRep(fe,'res sig full voxfit'); +% res = feGetRep(fe, 'res sig full voxfit',coords); +% res = feGetRep(fe, 'res sig full voxfit',voxelIndex); +%--------- +% Dimensions of the DW volume. +% dim = feGetRep(fe,'dims') +%--------- +% Dimensions of the maps of parameters and results. +% dims = feGetRep(fe, 'mapsize') +% +% End of feGetRep.m parameters, +% +% +% Copyright (2013-2014), Franco Pestilli, Stanford University, pestillifranco@gmail.com. + +val = []; + +% Format the input parameters. +param = lower(strrep(param,' ','')); + +% Start sorting the input and computing the output. +switch param + case 'name' + % Name of the current fe structure. + % + % name = feGetRep(fe,'name') + val = fe.rep.name; + + case 'type' + % The type of objes (always, fascicle evaluation) + % + % type = feGetRep(fe,'type') + val = fe.rep.type; % Always fascicle evaluation + + case 'dwi' + % Load the diffusion weighted data. + % + % dwi = feGetRep(fe,'dwirepeat') + val = dwiLoad(feGetRep(fe,'dwifile')); + + case 'dwifile' + % Load the repeated measure of the diffusion weighted data. + % + % dwiFile = feGetRep(fe,'dwirepeatfile') + val = fe.path.dwifilerep; + + case {'bvecs'} + % Diffusion directions. + % + % val = feGetRep(fe,'bvecs'); + val = fe.rep.bvecs; + + case {'bvecsindices'} + % Indices to the diffusion directions in the DWi 4th Dimension. + % + % val = feGetRep(fe,'bvecs indices rep'); + val = fe.rep.bvecsindices; + + case {'nbvecs','nbvals'} + % Number of B0's + % + % val = feGetRep(fe,'n bvals'); + val = length(feGetRep(fe,'bvals')); + + case {'bvals'} + % B0 Values. + % + % bval = feGetRep(fe,'bvals') + val = fe.rep.bvals; + + case {'diffusionsignalinvoxel','dsiinvox','dsigvox','dsigmeasuredvoxel'} + % Returns a nVoxels X nBvecs array of measured diffusion signal + % + % val = feGetRep(fe,'dsiinvox'); + % val = feGetRep(fe,'dsiinvox',voxelsIndices); + % val = feGetRep(fe,'dsiinvox',coords); + val = fe.rep.diffusion_signal_img(feGet(fe,'voxelsindices',varargin),:)'; + + case {'diffusionsignalinvoxeldemeaned','dsiinvoxdemeaned'} + % Returns a nVoxels X nBvecs array of demeaned diffusion signal + % + % val =feGetRep(fe,'dsiinvoxdemeaned'); + % val =feGetRep(fe,'dsiinvoxdemeaned',voxelsIndices); + % val =feGetRep(fe,'dsiinvoxdemeaned',coords); + nBvecs = feGetRep(fe,'nBvecs'); + voxelIndices = feGet(fe,'voxelsindices',varargin); + val = fe.rep.diffusion_signal_img(voxelIndices,:) - repmat(mean(fe.rep.diffusion_signal_img(voxelIndices,:), 2),1,nBvecs); + keyboard % THis seems to be worng + + case {'b0signalimage','b0vox'} + % Get the diffusion signal at 0 diffusion weighting (B0) for this voxel + % + % val = feGetRep(fe,'b0signalimage'); + % val = feGetRep(fe,'b0signalimage',voxelIndex); + % val = feGetRep(fe,'b0signalimage',coords); + val = fe.rep.diffusion_S0_img(feGet(fe,'voxelsindices',varargin), :); + + case {'isoweights','weightsiso','meanvoxelsignal'} + % Weights of the isotropic voxel signals, this is the mean signal in + % each voxel. + % + % val = feGetRep(fe,'iso weights'); + % val = feGetRep(fe,'iso weights'coords) + % val = feGetRep(fe,'iso weights',voxelIndices) + val = feGet(fe,'Miso') \ feGetRep(fe,'dsig full')'; + val = val(feGet(fe,'voxelsindices',varargin)); + + case {'dsigiso','isodsig'} + % mean signalin each voxel, returned for each diffusion direction: + % size(nBvecsxnVoxels, 1). + % + % val = feGetRep(fe,'iso disg'); + % val = feGetRep(fe,'iso disg',coords) + % val = feGetRep(fe,'iso dsig',voxelIndices) + val = feGetRep(fe,'iso weights'); + val = repmat(val,1,feGetRep(fe,'nbvecs'))'; + val = val(:); + + case {'dsigmeasured','dsigfull'} + % Measured signal in VOI, this is the raw signal. not demeaned + % + % dSig = feGetRep(fe,'dSig full') + val = fe.rep.diffusion_signal_img'; + val = val(:)'; + + % Return a subset of voxels + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'diffusionsignaldemeaned','dsigdemeaned'} + % Measured signal in VOI, demeaned, this is the signal used for the + % fiber-portion of the M model. + % + % dSig = feGetRep(fe,'dsigdemeaned'); + % dSig = feGetRep(fe,'dsigdemeaned',[1 10 100]); + % dSig = feGetRep(fe,'dsigdemeaned',coords); + nVoxels = feGet(fe,'nVoxels'); + nBvecs = feGetRep(fe,'nBvecs'); + val = (feGetRep(fe,'dsig measured') - reshape(repmat( ... + mean(reshape(feGetRep(fe,'dsig measured'), nBvecs, nVoxels),1),... + nBvecs,1), size(feGetRep(fe,'dsig measured'))))'; + % Return a subset of voxels + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'dsigrowssubset','diffusionsignaldemeanedinsubsetofrows'} + % Get the demeaned signal for a subset of rows. + % Useful for cross-validation. + % + % dSig = feGetRep(fe,'dsigrowssubset',voxelsList); + dSig = feGetRep(fe,'dsigdemeaned'); + for vv = 1:length(voxelsList) + val(feGet(fe,'voxel rows',vv)) = dSig(feGet(fe,'voxel rows',voxelList(vv))); + end + + case {'totalr2'} + % Return the global R2 (fraction of variance explained) of the full life + % model. + % + % R2 = feGetRep(fe,'total r2'); + + % measured = feGetRep(fe,'dsigdemeaned'); + % predicted = feGetRep(fe,'fiber p sig'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGetRep(fe,'diffusion signal demeaned') - ... + feGet(fe,'pSig fiber')).^2 ) ./ ... + sum((feGetRep(fe,'diffusion signal demeaned') - ... + mean(feGetRep(fe,'diffusion signal demeaned'))).^2) )); + + case {'totalr2voxelwise'} + % Return the global R2 (fraction of variance explained) of the full life + % model from a voxel-wise fit + % + % R2 = feGetRep(fe,'total r2'); + + % measured = feGetRep(fe,'dsigdemeaned'); + % predicted = feGetRep(fe,'p sig f voxel wise'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGetRep(fe,'diffusion signal demeaned')' - ... + feGet(fe,'pSig f voxel wise')).^2 ) ./ ... + sum((feGetRep(fe,'diffusion signal demeaned') - ... + mean(feGetRep(fe,'diffusion signal demeaned'))).^2) )); + + case {'totpve'} + % Total percent variance explained by data1 on data2 + % + % R2 = feGetRep(fe,'tot pve data') + val = 100 * feGetRep(fe,'total r2'); + + case {'totalr2data'} + % Return the global R2 (fraction of variance explained) of the full life + % model in data set 2 by data set 1. + % + % R2 = feGetRep(fe,'total r2 data'); + + % measured = feGetRep(fe,'dsigdemeaned'); + % predicted = feGetRep(fe,'fiber p sig'); + % val = (1 - (sum((measured - predicted).^2 ) ./ ... + % sum((measured - mean(measured)).^2) )); + val = (1 - (sum((feGetRep(fe,'diffusion signal demeaned') - ... + feGet(fe,'diffusion signal demeaned')).^2 ) ./ ... + sum((feGetRep(fe,'diffusion signal demeaned') - ... + mean(feGetRep(fe,'diffusion signal demeaned'))).^2) )); + + case {'totpvedata'} + % Total percent variance explained by data1 on data2 + % + % R2 = feGetRep(fe,'tot pve data') + val = 100 * feGetRep(fe,'total r2 data'); + + case {'totalrmsedata'} + % Global root mean squared error of data1 on data 2 + % + % rmse = feGetRep(fe,'rmse data') + val = sqrt(mean((feGetRep(fe,'diffusion signal demeaned') - ... + feGet(fe,'diffusion signal demeaned')).^2)); + + case {'totalrmseratio'} + % Global ratio of root mean squared error of Model/Data + % + % rmse = feGetRep(fe,'rmse data ratio') + val = feGetRep(fe,'total rmse') ./ feGetRep(fe,'total rmse data'); + + case {'totalrmseratiovoxelwise'} + % Global ratio of root mean squared error of Model/Data from a + % voxel-wise fit + % + % rmse = feGetRep(fe,'totalrmseratiovoxelwise') + val = feGetRep(fe,'total rmse voxelwise') ./ feGetRep(fe,'total rmse data'); + + case {'totalrmse','rmsetotal'} + % Root mean squared error of the LiFE fit to the whole data + % + % rmse = feGetRep(fe,'rmsetotal') + val = sqrt(mean((feGetRep(fe,'diffusion signal demeaned') - ... + feGet(fe,'psigfiber')).^2)); + + case {'totalrmsevoxelwise'} + % Root mean squared error of the LiFE fit to the whole data from a + % voxel-wise fit + % + % rmse = feGetRep(fe,'totalrmsevoxelwise') + val = sqrt(mean((feGetRep(fe,'diffusion signal demeaned')' - ... + feGet(fe,'psigfvoxelwise')).^2)); + + case {'ressigfiber'} + % Residual signal fiber prediction - measured_demeaned. + % + % res = feGetRep(fe,'res sig fiber') + val = (feGetRep(fe,'dsigdemeaned') - feGet(fe,'psig fiber')); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'ressigfull'} + % Residual signal full model prediction - measured signal. + % + % res = feGetRep(fe,'res sig full'); + % res = feGetRep(fe, 'res sig full',coords); + % res = feGetRep(fe, 'res sig full',voxelIndex); + val = (feGetRep(fe,'dsig full') - feGet(fe,'psig full')'); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'ressigfullvoxelwise'} + % Residual signal full model prediction from a multi-voxel fit. + % + % res = feGetRep(fe,'res sig full voxfit'); + % res = feGetRep(fe, 'res sig full voxfit',coords); + % res = feGetRep(fe, 'res sig full voxfit',voxelIndex); + %tic,val = feGetRep(fe,'dsig demeaned') - feGet(fe,'psigfvoxelwise') + feGetRep(fe,'dsigiso');toc + val = feGetRep(fe,'dsig full') - feGet(fe,'psigfvoxelwise'); + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'voxressigfullvoxelwise'} + % Residual signal full model prediction from a multi-voxel fit. + % ORganized in nvecsxn + % + % res = feGetRep(fe,'voxressigfullvoxelwise'); + % res = feGetRep(fe, 'voxressigfullvoxelwise',coords); + % res = feGetRep(fe, 'voxressigfullvoxelwise',voxelIndex); + %tic,val = feGetRep(fe,'dsig demeaned') - feGet(fe,'psigfvoxelwise') + feGetRep(fe,'dsigiso');toc + val = reshape(feGetRep(fe,'ressigfullvoxelwise'),feGetRep(fe,'nbvecs'),feGet(fe,'nvoxels')); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:,feGet(fe,'voxelsindices',varargin)); + end + + case {'voxisoweights','voxweightsiso','voxmeanvoxelsignal'} + % Weights of the isotropic voxel signals, this is the mean signal in + % each voxel. + % Organized nBvecs x nVoxels + % + % val = feGet(fe,'voxiso weights'); + % val = feGet(fe,'voxiso weights'coords) + % val = feGet(fe,'voxiso weights',voxelIndices) + val = feGet(fe,'Miso') \ feGetRep(fe,'dsig full')'; + val = repmat(val,1,feGet(fe,'nbvecs'))'; + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:,feGet(fe,'voxelsindices',varargin)); + end + + case {'fiberressigwithmean'} + % Residual signal fiber model prediction - demeaned measured signal + % with added mean signal. VECTOR FORM. + % + % This is used to reconstruct an image (volume) to be used for the + % refinement process. + % + % res = feGetRep(fe,'fiber res sig with mean'); + + % predicted = feGet(fe,'psig fiber'); + % measured = feGetRep(fe,'dsigdemeaned'); + % val = (measured_full - predicted demeaned); + val = (feGetRep(fe,'dsig full')' - feGet(fe,'psig fiber')); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(feGet(fe,'voxel rows',feGet(fe,'voxelsindices',varargin))); + end + + case {'predictedfullsignalvoxel','psigfullvox'} + % Predicted signal by the full model in a set of voxeles. + % + % Vox subfield stores per voxel within the VOI + % The pSig has size of the dwi. + % It is stored as val = pSig(X,Y,Z,Theta) + % + % pSig = feGetRep(fe, 'pSig full by voxel'); + % pSig = feGetRep(fe, 'pSig full by voxel',coords); + % pSig = feGetRep(fe, 'pSig full by voxel',voxelIndex); + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'pSig full'), nBvecs, nVoxels); + + case {'voxelr2','r2vox','voxr2','r2byvoxel'} + % Return a column vector of the proportion of variance explained in + % each voxel. + % + % R2byVox = feGetRep(fe,'voxr2'); + % R2byVox = feGetRep(fe,'voxr2',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + nBvecs = feGetRep(fe,'nBvecs'); + val = (1 - (sum((measured - predicted).^2 ) ./ ... + sum((measured - repmat(mean(measured), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelss','ssvox','voxss','sumofsquaresbyvoxel'} + % Return a column vector of sum of squares error of the model + % prediction in each voxel + % + % ssem = feGetRep(fe,'voxss'); + % ssem = feGetRep(fe,'voxss',coords); + predicted = feGet(fe,'pSig f vox'); + measured = feGetRep(fe,'dSig demeaned by voxel'); + val = sum((measured - predicted).^2 ); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelssdata','ssvoxdata','voxssdata','sumofsquaresbyvoxeldata'} + % Return a column vector of sum of squares error of the data in + % each voxel + % + % ssed = feGetRep(fe,'voxssedata'); + % ssed = feGetRep(fe,'voxssdata',coords); + measured1 = feGet(fe,'dSig demeaned by voxel'); + measured2 = feGetRep(fe,'dSig demeaned by voxel'); + val = sum((measured2 - measured1).^2 ); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2data','r2voxdata','voxr2data','r2byvoxeldata'} + % Return a column vector of the proportion of variance explained in + % each voxel in data set 2 given the data in dataset 1. + % + % R2byVox = feGetRep(fe,'voxr2data'); + % R2byVox = feGetRep(fe,'voxr2data',coords); + measured1 = feGet(fe,'dSig demeaned by voxel'); + measured2 = feGetRep(fe,'dSig demeaned by voxel'); + nBvecs = feGetRep(fe,'nBvecs'); + val = (1 - (sum((measured2 - measured1).^2 ) ./ ... + sum((measured2 - repmat(mean(measured2), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zero','r2voxzero','voxr2zero','r2byvoxelzero'} + % Return a column vector of the proportion of variance explained in + % each voxel. (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGetRep(fe,'voxr2zero'); + % R2byVox = feGetRep(fe,'voxr2zero',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + val = (1 - (sum((measured - predicted).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2pearson','r2voxpearson','voxr2corr','r2byvoxelpearson'} + % Return a column vector of the squre of the pearson correlation coefficient + % + % R2byVox = feGetRep(fe,'voxr2corr'); + % R2byVox = feGetRep(fe,'voxr2corr',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f vox'); + val = corrcoef(measured - predicted).^2; + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zerodata','r2voxzerodata','voxr2zerodata','r2byvoxelzerodata'} + % Return a column vector of the proportion of variance explained in + % each voxel in dataset 1 given the data in data set 2. + % (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGetRep(fe,'voxr2zerodata'); + % R2byVox = feGetRep(fe,'voxr2zerodata',coords); + measured = feGet(fe,'dSig demeaned by voxel'); + measured2 = feGetRep(fe,'dSig demeaned by voxel'); + val = (1 - (sum((measured - measured2).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + + case {'voxelr2voxelwise','r2voxvoxelwise','voxr2voxelwise','r2voxelwisebyvoxel'} + % Return a column vector of the proportion of variance explained in + % each voxel. + % + % R2byVox = feGetRep(fe,'voxr2voxelwise'); + % R2byVox = feGetRep(fe,'voxr2voxelwise',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f voxel wise by voxel'); + nBvecs = feGetRep(fe,'nBvecs'); + val = (1 - (sum((measured - predicted).^2 ) ./ ... + sum((measured - repmat(mean(measured), nBvecs,1)).^2 ) )); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelr2zerovoxelwise','r2zerovoxelwisebyvoxel','voxr2zerovoxelwise'} + % Return a column vector of the proportion of variance explained in + % each voxel. (Normalized to the squared diffusion signal in each voxel) + % + % R2byVox = feGetRep(fe,'voxr2zerovoxelwise'); + % R2byVox = feGetRep(fe,'voxr2zerovoxelwise',coords); + measured = feGetRep(fe,'dSig demeaned by voxel'); + predicted = feGet(fe,'pSig f voxel wise by voxel'); + val = (1 - (sum((measured - predicted).^2 ) ./ sum(measured.^2))); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelvarianceexplained','varexpvox','voxvarexp','varexpbyvoxel'} + % Return the percent of varince explained in each voxel. + % + % R2byVox = feGetRep(fe,'var exp by voxel'); + % R2byVox = feGetRep(fe,'var exp by voxel',coords); + val = 100.*feGetRep(fe,'voxr2'); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelvarianceexplaineddata','varexpvoxdata','voxvarexpdata','varexpbyvoxeldata'} + % Return the percent of variance explained in each voxel in data set 1 + % given the data in data set 2. + % + % R2byVox = feGetRep(fe,'var exp by voxel data'); + % R2byVox = feGetRep(fe,'var exp by voxel data',coords); + val = 100.*feGetRep(fe,'voxr2 data'); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'dsigdemeanedbyvoxel','dsigdemeanedvox'} + % Demeaned diffusion signal in each voxel + % + % dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel'); + % dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel',coords); + % dSigByVoxel = feGetRep(fe,'dsigdemeaned by Voxel',vxIndex); + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'dsigdemeaned'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin)); + + case {'dsigfullbyvoxel','dsigfullvox'} + % Full (measured) signal in each voxel + % + % dSigByVoxel = feGetRep(fe,'dSig full by Voxel'); + % dSigByVoxel = feGetRep(fe,'dSig full by Voxel',coords); + % dSigByVoxel = feGetRep(fe,'dSig full by Voxel',vxIndex); + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'dSig full'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'voxelrmse','voxrmse'} + % A volume of RMSE values + % + % RMSE = feGetRep(fe,'vox rmse') + % RMSE = feGetRep(fe,'vox rmse',coords) + % RMSE = feGetRep(fe,'vox rmse',vxIndex) + measured = feGetRep(fe,'dsigdemeaned by voxel'); + predicted = feGetOLD(fe,'pSig f vox'); + val = sqrt(mean((measured - predicted).^2,1)); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelrmsevoxelwise','voxrmsevoxelwise'} + % A volume of RMSE values optained with the voxel-wise (vw) fit. + % + % RMSE = feGetRep(fe,'vox rmse vw') + % RMSE = feGetRep(fe,'vox rmse vw',coords) + % RMSE = feGetRep(fe,'vox rmse vw',vxIndex) + measured = feGetRep(fe,'dsigdemeaned by voxel'); + predicted = feGet(fe,'pSig f voxel wise by voxel'); + val = sqrt(mean((measured - predicted).^2,1)); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelrmseratio','voxrmseratio'} + % A volume with the ratio of the RMSE of model/data + % + % rmseRatio = feGetRep(fe,'vox rmse ratio') + % rmseRatio = feGetRep(fe,'vox rmse ratio',coords) + % rmseRatio = feGetRep(fe,'vox rmse ratio',vxIndex) + rmseData = feGetRepOLD(fe,'vox rmse data'); + rmseModel = feGetRepOLD(fe,'vox rmse'); + val = rmseModel ./ rmseData; + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'prmseratio','proportionrmseratio'} + % The probability of a ratio-value in the volume. + % Default across 25 log-distributed bins between [.5,2] + % + % rmseRatio = feGetRep(fe,'p rmse ratio') + % + % % Change the bins over whih the proportions are computed: + % bins = logspace(log10(.25),log10(4),50) + % rmseRatio = feGetRep(fe,'p rmse ratio',bins) + if isempty(varargin) + bins = logspace(log10(.5),log10(2),25); + end + % Extract the rmse ratio in each voxel + Rrmse = feGetRep(fe,'vox rmse ratio'); + % Compute the number of occurrences for a range of values. + [val(1,:),val(2,:)] = hist(Rrmse,bins); + val(1,:) = val(1,:)./sum(val(1,:)); + + case {'voxelrmseratiovoxelwise','voxrmseratiovoxelwise'} + % A volume with the ratio of the RMSE of model/data + % + % rmseRatio = feGetRep(fe,'vox rmse ratio voxel wise') + % rmseRatio = feGetRep(fe,'vox rmse ratio voxel wise',coords) + % rmseRatio = feGetRep(fe,'vox rmse ratio voxel wise',vxIndex) + rmseData = feGetRep(fe,'vox rmse data'); + rmseModel = feGetRep(fe,'vox rmse voxel wise'); + val = rmseModel ./ rmseData; + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelrmsedata','voxrmsedata'} + % A volume of RMSE values from data set 1 to data set 2 + % + % RMSE = feGetRep(fe,'vox rmse data') + % RMSE = feGetRep(fe,'vox rmse data',coords) + % RMSE = feGetRep(fe,'vox rmse data',vxIndex) + measured = feGet(fe,'dsigdemeaned by voxel'); + measured2 = feGetRep(fe,'dsigdemeaned by voxel'); + val = sqrt(mean((measured - measured2).^2,1)); + val = val(feGet(fe,'return voxel indices',varargin)); + + case {'voxelrmsetest','voxrmsetest'} + % A volume of RMSE values with a subset of fibers' weights set to 0. + % + % RMSE = feGetRep(fe,'vox rmse',fiberIndices) + % RMSE = feGetRep(fe,'vox rmse',fiberIndices,coords) + % RMSE = feGetRep(fe,'vox rmse',fiberIndices,voxelIndex) + measured = feGetRep(fe,'dsigdemeaned by voxel'); + % Reshape the predicted signal by voxles + predicted = reshape(feGet(fe,'pSig fiber test voxel wise',varargin{1}), feGetRep(fe,'nBvecs'), feGet(fe,'nVoxels')); + val = sqrt(mean((measured - predicted).^2,1)); + + if length(varargin) == 2 + val = val(feGet(fe,'return voxel indices',varargin)); + end + + case {'voxelrmsetestvoxelwise','voxrmsetestvoxelwise'} + % A volume of RMSE values with a subset of fibers' weights set to 0. + % + % RMSE = feGetRep(fe,'voxel rmse test voxel wise',fiberIndices) + % RMSE = feGetRep(fe,'voxel rmse test voxel wise',fiberIndices,coords) + % RMSE = feGetRep(fe,'voxel rmse test voxel wise',fiberIndices,voxelIndex) + measured = feGetRep(fe,'dsigdemeaned by voxel'); + % Reshape the predicted signal by voxles + predicted = reshape(feGet(fe,'pSig fiber test voxel wise',varargin{1}), feGetRep(fe,'nBvecs'), feGet(fe,'nVoxels')); + val = sqrt(mean((measured - predicted).^2,1)); + + if length(varargin) == 2 + val = val(feGet(fe,'return voxel indices',varargin)); + end + + case {'residualsignalfibervoxel','resfibervox'} + % Fibers' residual signal by voxel + % + % res = feGetRep(fe,'res sig fiber vox') + % res = feGetRep(fe,'res sig fiber vox',coords) + % res = feGetRep(fe,'res sig fiber vox',vxIndex) + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'res sig fiber'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'residualsignalfullvoxel','resfullvox'} + % Full (measured) residual signal by voxel + % + % res = feGetRep(fe,'res sig full vox') + % res = feGetRep(fe,'res sig full vox',coords) + % res = feGetRep(fe,'res sig full vox',vxIndex) + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'res sig full'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'fiberressigwithmeanvoxel'} + % Residual signal fiber model prediction - demeaned measured signal + % with added mean signal. VOXEL FORM (nBvecs x nVoxel). + % + % This is used to reconstruct an image (volume) to be used for the + % refinement process. + % + % res = feGetRep(fe,'fiber res sig with mean'); + + % predicted = feGet(fe,'psig fiber'); + % measured = feGetRep(fe,'dsigdemeaned'); + % val = (measured - predicted) + (measured_full - measured); + val = feGetRep(fe,'fiberressigwithmean'); + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(val, nBvecs, nVoxels); + + if ~isempty(varargin) + % voxelIndices = feGet(fe,'voxelsindices',varargin); + % voxelRowsToKeep = feGet(fe,'voxel rows',voxelIndices); + % val = val(voxelRowsToKeep,:); + val = val(:, feGet(fe,'return voxel indices',varargin)); + end + + case {'fiberressigwithmeanvox','resfibermeanvox'} + % Fibers' residual signal by voxel with mean signal added (with added + % isotropic component). + % + % This is used to compute the residual signal for the refinement. + % + % res = feGetRep(fe,'fiber res sig with mean vox') + % res = feGetRep(fe,'fiber res sig with mean vox',coords) + % res = feGetRep(fe,'fiber res sig with mean vox',vxIndex) + nBvecs = feGetRep(fe,'nBvecs'); + nVoxels = feGet(fe,'n voxels'); + val = reshape(feGetRep(fe,'fiber res sig with mean'), nBvecs, nVoxels); + val = val(:,feGet(fe,'return voxel indices',varargin))'; + + case {'volumesize','dims','dim','imagedim'} + % Dimensions of the DW volume. + % + % dim = feGetRep(fe,'dims') + val = fe.rep.imagedim; + case {'mapsize'} + % Dimensions of the maps of parameters and results. + % + % dims = feGetRep(fe, 'mapsize') + val = fe.rep.imagedim(1:3); + + otherwise + help('feGetRep') + fprintf('[feGetRep] Unknown parameter << %s >>...\n',param); + keyboard +end + +end % END MAIN FUNCTION diff --git a/fe/feSet.m b/fe/feSet.m new file mode 100755 index 0000000..255428e --- /dev/null +++ b/fe/feSet.m @@ -0,0 +1,197 @@ +function fe = feSet(fe,param,val,varargin) +% Set fascicle evaluation parameters. +% +% fe = feSet(fe,param,val,varargin) +% +%---------- +% feSet(fe,'bvecsindices'); +%---------- +% Set the a second diffusion signla measuremnt (repeat). +% Image_vals is the image array with the dwi signal taken from all the +% voxels in the new dataset the fe.roi +% fe = feSet(fe,'diffusion signal repeat',image_vals); +%---------- +% Set the the s0 (no diffusion direction measurement) for a second +% diffusion signla measuremnt (repeat). +% Image_vals is the image array with the dwi signal taken from all the +% voxels in the new dataset the fe.roi +% fe = feSet(fe,'b0signalrepeat',image_vals); +%---------- +% +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + +% Check for input parameters +if notDefined('fe'), error('fe structure required'); end +if notDefined('param'), error('param required'); end +if ~exist('val','var'), error('Value required'); end + +% Squeeze out spaces and force lower case +param = mrvParamFormat(param); + +%% +switch param + % Book-keeping + case 'name' + fe.name = val; % This one's name + case 'type' + fe.type = 'faseval'; % Always fascicle evaluation + case 'savedir' + fe.path.savedir = val; % Always fascicle evaluation + + % Set top level structure, not just single slot + case 'life' + fe.life = val; % Structure of parameters and results from LIFE analysis + + case 'fgfromacpc' + % Fiber group candidate fascicles, Connectome. + % Everything isin img coordinates in LiFE + fe.fg = dtiXformFiberCoords(val, fe.life.xform.acpc2img,'img'); + % Must clear when we change the fg + fe = feSet(fe,'voxel 2 fiber node pairs',[]); + + case {'fgimg', 'fg'} + % Fiber group candidate fascicles, Connectome. + % Everything is in img coordinates in LiFE + % + fe.fg = val; + % Must clear when we change the fg + fe = feSet(fe,'voxel 2 fiber node pairs',[]); + + case {'fgtensors','tensors','fgq','q'} + % fe = feSet(fe, 'tensors', tensors); - set the passed tensors + fe.life.fibers.tensors = val; + + case 'roi' + % Cell array of regions of interest where we evaluate + % Must clear v2fnp + fe.roi = val; + fe = feSet(fe,'v2fnp',[]); + + case {'roifromfg','fgroi','roifg'} + name = sprintf('roi_%s',fe.fg.name); + randColor = rand(1,3); + fe.roi = dtiNewRoi(name,randColor,fefgGet(feGet(fe,'fg img'),'unique image coords')); + + case 'xform' + fe.life.xform = val; % Transforms between coords for fg, roi, and dwi data + + %% Diffusion data related parameters + case {'bvecs','diffusionbvecs'} + % feSet(fe,'bvecs'); + fe.life.bvecs = val; + case {'bvecsindices','diffusionimagesindicesindwivolume'} + % feSet(fe,'bvecsindices'); + fe.life.bvecsindices = val; + case {'bvals','diffusionbvals'} + fe.life.bvals = val; + case {'diffusionsignalimage','dsi', 'diffusion_signal_img'} + fe.life.diffusion_signal_img = val; + case {'b0signalimage','b0img', 'diffusion_s0_im','s0image'} + fe.life.diffusion_S0_img = val; + case {'usedvoxels'} + fe.life.usedVoxels = val; + case {'modeltensor'} + fe.life.modelTensor = val; + case {'roivoxels','roicoords'} + % What space? What form for the coords? + % Always in IMG coords in LiFE. + fe.roi.coords = val; + + + %% The LiFE model + case 'mfiber' + fe.life.Mfiber = val; % Fiber portion of M matrix + case {'measuredsignalfull', 'dsigmeasured'} % Measured signal in ROI + fe.life.dSig = val; + case 'fit' + fe.life.fit = val; + case 'voxfit' + fe.life.voxfit = val; + case 'xvalfit' + fe.life.xvalfit = val; + + %% Connectome fibers information. + case {'numberofuniquefibersineachvoxel','uniquefibersnum','numberofuniquefibers','numuniquef'} + fe.life.fibers.unique.num = val; + case {'indextouniquefibersineachvoxel','uniquefibersindex','uniqueindex','indexesofuniquefibers','indexuniquef','uniquefibers'} + fe.life.fibers.unique.index = val; + case {'numberoftotalfibersineachvoxel','totalfibernmber','fibersnum','numberoffibers','numf','numfibers'} + fe.life.fibers.total.num = val; + case {'indexoftotalfibersineachvoxel','totalfiberindex','fibersbyvox','fibersinvox'} + fe.life.fibers.total.index = val; + case {'voxel2fibernodepairs','v2fnp'} + % This has to be cleared whenever we change fg or roi + fe.life.voxel2FNpair = val; + % Spatial coordinate transforms for voxels and fg to coordinate frames + case {'xformimg2acpc','img2acpc','img2acpcxform'} + fe.life.xform.img2acpc = val; + case {'xformacpc2img','acpc2img','acpc2imgxform'} + fe.life.xform.acpc2img = val; + case {'size','imgsize','volumesize','dims','dim'} + fe.life.imagedim = val; + + %% Diffusion data reapeted measure parameters + case 'dwirepeatfile' + fe.path.dwifilerep = val; % Diffusion weighted file used for testing results + case {'diffusionsignalimagerepeat'} + % Set the a second diffusion signla measuremnt (repeat). + % + % Image_vals is the image array with the dwi signal taken from all the + % voxels in the new dataset the fe.roi + % + % fe = feSet(fe,'diffusion signal repeat',image_vals); + fe.rep.diffusion_signal_img = val; + case {'s0imagerepeat'} + % Set the the s0 (no diffusion direction measurement) for a second + % diffusion signla measuremnt (repeat). + % + % Image_vals is the image array with the dwi signal taken from all the + % voxels in the new dataset the fe.roi + % + % fe = feSet(fe,'b0signalrepeat',image_vals); + fe.rep.diffusion_S0_img = val; + case {'bvecsrepeat','diffusionbvecsrepeat'} + % feSet(fe,'bvecsrepeat'); + fe.rep.bvecs = val; + case {'bvecsindicesrepeat','diffusionimagesindicesindwivolumerepeat'} + % feSet(fe,'bvecsindicesrepeat'); + fe.rep.bvecsindices = val; + case {'bvalsrepeat','diffusionbvalsrepeat'} + % fe = feSet(fe,'bvalsrepeat') + fe.rep.bvals = val; + case {'imgsizerepeat'} + fe.rep.imagedim = val; + + case {'anatomyfile'} + fe.path.anatomy = val; + case 'dwifile' + fe.path.dwifile = val; % Diffusion weighted file used for testing results + case 'dtfile' + fe.path.dtfile = val; % Diffusion weighted file used for testing results + case 'dictionaryparameters' + fe.life.M.Nphi = val{1}; + fe.life.M.Ntheta = val{2}; + fe.life.M.orient = val{3}; + fe.life.M.DictSig = val{4}; + case 'gradients' + fe.life.fibers.grad = val{1}; + fe.life.fibers.Nelem = val{2}; + case 'indicationtensor' + fe.life.M.Phi = val; + case 'atomslist' %% To revise if can be avoided + fe.life.fibers.atoms_list = val; + case 'voxelslist' %% To revise if can be avoided + fe.life.fibers.voxels_list = val; + case 'nelem' %% To revise if can be avoided + fe.life.fibers.Nelem = val; + case 'ms0' + fe.life.M.S0 = val; + + + otherwise + error('Unknown parameter %s\n',param); +end + +end diff --git a/scripts/life_demo.m b/scripts/life_demo.m new file mode 100755 index 0000000..1fa3f0d --- /dev/null +++ b/scripts/life_demo.m @@ -0,0 +1,415 @@ +function [fh, fe] = life_BD_demo() +%% Example of initialization and fitting of the Big Data (BD) LiFE model (LiFE-BD) +% This demo function illustrates how to: +% - A - Set up a LiFE-BD structure, identified as 'fe' (fascicle evaluation) in +% the code below. This model contains a prediction of the diffusion +% measurements in each white-matter voxel given by the fascicles contained +% in a tractogrpahy solution, the connectome. Each fascicle makes a +% prediction about the direction of diffusion in the set of voxels where +% it travels through. The prediction is generated given the fascicle +% orientation and position inside the voxel. Predictions from multiple +% fascicles in each voxels are combined to generate a global connectome +% prediciton for the diffusion signal in large sets of white matter +% voxels. +% - B - Fit the LiFE-BD model to compute the weights associated to each fascicle +% in the connectome. Fascicles in the conenctome contribute differently to +% predicting the diffusion signal in each voxel. First of all, fascicles +% make predictions about the diffusion only in voxels where they travel. +% Secondly, some fascicles have paths that produce better diffusion +% predictions than others. We use a least-square method to find the +% contribution of each fascicle to the diffusion signal in the white +% matter voxels where the fascicles travels. A single weight is assigned +% to each fascicle representing the global contribution of the fasicle to +% the signal of all the voxels along its path - we call this +% fascicle-global. Because multiple fascicles exist in several voxels the +% set of fascicles weights and fascicles predicitons represents the +% connectome-global prediction of the diffusion signal within the entire +% set of white matter voxels. Estimating the fascicle weights allows for +% evaluating the quality of the tractography solution. Eliminating +% fascicles that do not contribute to predicting the diffusion signal +% (they have assigned a zreo-weight). Finaly, the root-mean-squared error +% (RMSE) of the model to the diffusion data - the model prediction error - +% is used to evaluate the model prediction quality, compare different +% tractography models and to perform statistical inference on the on +% properties of the connectomes. +% - C - Compare two different connectome models. This demo will show how to +% compare two different conenctome models by using the diffusion +% prediction error (the Root-Mean-Squared Error, RMSE). We report the +% example of two conenctomes one generated using Constrained-spherical +% deconvolution (CSD) and probabilistic tractography the other using a +% tensor model and deterministic tractography +% - Note - The example connectomes used for this demo comprise a portion +% of the right occiptial lobe of an individual human brain. LiFE-BD utilizes +% large-scale methods optimized for an efficient use of memory to solve the +% foward model. The software allows for solving connectomes spanning the +% entire white-matter of idnvidual brains. The size of the connectome on +% the test data set is small enought to allow for testing the code within +% a few minutes requiring only about 10GB of computer RAM and standard +% hardaware. This code has been tested with: +% + +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com + +% Intialize a local matlab cluster if the parallel toolbox is available. +% This helps speeding up computations espacially for large conenctomes. + +%feOpenLocalCluster; + +%% Build the file names for the diffusion data, the anatomical MRI. +dwiFile = fullfile(lifeDemoDataPath('diffusion'),'life_demo_scan1_subject1_b2000_150dirs_stanford.nii.gz'); +dwiFileRepeat = fullfile(lifeDemoDataPath('diffusion'),'life_demo_scan2_subject1_b2000_150dirs_stanford.nii.gz'); +t1File = fullfile(lifeDemoDataPath('anatomy'), 'life_demo_anatomy_t1w_stanford.nii.gz'); + +%% (1) Evaluate the Probabilistic CSD-based connectome. +% We will analyze first the CSD-based probabilistic tractography +% connectome. +prob.tractography = 'Probabilistic'; +fgFileName = fullfile(lifeDemoDataPath('tractography'), ... + 'life_demo_mrtrix_csd_lmax10_probabilistic.mat'); + +% The final connectome and data astructure will be saved with this name: +feFileName = 'LiFE-BD_build_model_demo_CSD_PROB'; + +%% (1.1) Initialize the LiFE-BD model structure, 'fe' in the code below. +% This structure contains the forward model of diffusion based on the +% tractography solution. It also contains all the information necessary to +% compute model accuracry, and perform statistical tests. You can type +% help('feBuildModel') in the MatLab prompt for more information. + +N = 360; % Discretization parameter + +mycomputer = computer(); +release = version('-release'); +switch strcat(mycomputer,'_',release) + case {'GLNXA64_2015a','MACI64_2014b'} + fe = feConnectomeInit(dwiFile,fgFileName,feFileName,[],dwiFileRepeat,t1File,N,[1,0],0); + otherwise + sprintf('WARNING: currently LiFE is optimized for an efficient usage of memory \n using the Sparse Tucker Decomposition aproach (Caiafa&Pestilli, 2015) \n ONLY for Linux (MatlabR2015a) and MacOS (MatlabR2014b). \n If you have a different system or version you can still \n use the old version of LiFE (memory intensive). \n\n') + sprintf('\n Starting building big matrix M in OLD LiFE...\n') + fe = feConnectomeInit(dwiFile,fgFileName,feFileName,[],dwiFileRepeat,t1File,N,[1,0],1); +end + +%% (1.2) Fit the model. +% Hereafter we fit the forward model of tracrography using a least-squared +% method. The information generated by fitting the model (fiber weights +% etc) is then installed in the LiFE-BD structure. + +fe = feSet(fe,'fit',feFitModel(feGet(fe,'model'),feGet(fe,'dsigdemeaned'),'bbnnls')); + +%% (1.3) Extract the RMSE of the model on the fitted data set. +% We now use the LiFE-BD structure and the fit to compute the error in each +% white-matter voxel spanned by the tractography model. +prob.rmse = feGet(fe,'vox rmse'); + +%% (1.4) Extract the RMSE of the model on the second data set. +% Here we show how to compute the cross-valdiated RMSE of the tractography +% model in each white-matter voxel. We store this information for later use +% and to save computer memory. +prob.rmsexv = feGetRep(fe,'vox rmse'); + +%% (1.5) Extract the Rrmse. +% We show how to extract the ratio between the model prediction error +% (RMSE) and the test-retest reliability of the data. +prob.rrmse = feGetRep(fe,'vox rmse ratio'); + +%% (1.6) Extract the fitted weights for the fascicles. +% The following line shows how to extract the weight assigned to each +% fascicle in the connectome. +prob.w = feGet(fe,'fiber weights'); + +%% (1.7) Plot a histogram of the RMSE. +% We plot the histogram of RMSE across white-mater voxels. +[fh(1), ~, ~] = plotHistRMSE(prob); + +%% (1.8) Plot a histogram of the RMSE ratio. +% As a reminder the Rrmse is the ratio between data test-retest reliability +% and model error (the quality of the model fit). +[fh(2), ~] = plotHistRrmse(prob); + +%% (1.9) Plot a histogram of the fitted fascicle weights. +[fh(3), ~] = plotHistWeights(prob); +clear fe + +switch strcat(mycomputer,'_',release) + case {'GLNXA64_2015a','MACI64_2014b'} + fe = feConnectomeInit(dwiFile,fgFileName,feFileName,[],dwiFileRepeat,t1File,N,[1,0],0); + otherwise + sprintf('WARNING: currently LiFE is optimized for an efficient usage of memory \n using the Sparse Tucker Decomposition aproach (Caiafa&Pestilli, 2015) \n ONLY for Linux (MatlabR2015a) and MacOS (MatlabR2014b). \n If you have a different system or version you can still \n use the old version of LiFE (memory intensive). \n\n') + sprintf('\n Starting building big matrix M in OLD LiFE...\n') + fe = feConnectomeInit(dwiFile,fgFileName,feFileName,[],dwiFileRepeat,t1File,N,[1,0],1); +end + + +%% Extract the coordinates of the white-matter voxels +% We will use this later to compare probabilistic and deterministic models. +p.coords = feGet(fe,'roi coords'); +clear fe + +%% (2) Evaluate the Deterministic tensor-based connectome. +% We will now analyze the tensor-based Deterministic tractography +% connectome. +det.tractography = 'Deterministic'; +fgFileName = fullfile(lifeDemoDataPath('tractography'), ... + 'life_demo_mrtrix_tensor_deterministic.mat'); + +% The final connectome and data astructure will be saved with this name: +feFileName = 'LiFE-BD_build_model_demo_TENSOR_DET'; + +%% (2.1) Initialize the LiFE-BD model structure, 'fe' in the code below. +% This structure contains the forward model of diffusion based on the +% tractography solution. It also contains all the information necessary to +% compute model accuracry, and perform statistical tests. You can type +% help('feBuildModel') in the MatLab prompt for more information. +clear fe +switch strcat(mycomputer,'_',release) + case {'GLNXA64_2015a','MACI64_2014b'} + fe = feConnectomeInit(dwiFile,fgFileName,feFileName,[],dwiFileRepeat,t1File,N,[1,0],0); + otherwise + sprintf('WARNING: currently LiFE is optimized for an efficient usage of memory \n using the Sparse Tucker Decomposition aproach (Caiafa&Pestilli, 2015) \n ONLY for Linux (MatlabR2015a) and MacOS (MatlabR2014b). \n If you have a different system or version you can still \n use the old version of LiFE (memory intensive). \n\n') + sprintf('\n Starting building big matrix M in OLD LiFE...\n') + fe = feConnectomeInit(dwiFile,fgFileName,feFileName,[],dwiFileRepeat,t1File,N,[1,0],1); +end + + + +%% (2.2) Fit the model. +% Hereafter we fit the forward model of tracrography using a least-squared +% method. The information generated by fitting the model (fiber weights +% etc) is then installed in the LiFE-BD structure. +fe = feSet(fe,'fit',feFitModel(feGet(fe,'model'),feGet(fe,'dsigdemeaned'),'bbnnls')); + +%% (2.3) Extract the RMSE of the model on the fitted data set. +% We now use the LiFE-BD structure and the fit to compute the error in each +% white-matter voxel spanned by the tractography model. +det.rmse = feGet(fe,'vox rmse'); + +%% (2.4) Extract the RMSE of the model on the second data set. +% Here we show how to compute the cross-valdiated RMSE of the tractography +% model in each white-matter voxel. We store this information for later use +% and to save computer memory. +det.rmsexv = feGetRep(fe,'vox rmse'); + +%% (2.5) Extract the Rrmse. +% We show how to extract the ratio between the model prediction error +% (RMSE) and the test-retest reliability of the data. +det.rrmse = feGetRep(fe,'vox rmse ratio'); + +%% (2.6) Extract the fitted weights for the fascicles. +% The following line shows how to extract the weight assigned to each +% fascicle in the connectome. +det.w = feGet(fe,'fiber weights'); + +%% (2.7) Plot a histogram of the RMSE. +% We plot the histogram of RMSE across white-mater voxels. +[fh(1), ~, ~] = plotHistRMSE(det); + +%% (2.8) Plot a histogram of the RMSE ratio. +% As a reminder the Rrmse is the ratio between data test-retest reliability +% and model error (the quality of the model fit). +[fh(2), ~] = plotHistRrmse(det); + +%% (2.9) Plot a histogram of the fitted fascicle weights. +[fh(3), ~] = plotHistWeights(det); + +%% Extract the coordinates of the white-matter voxels. +% We will use this later to compare probabilistic and deterministic models. +d.coords = feGet( fe, 'roi coords'); +clear fe + +%% (3) Compare the quality of fit of Probabilistic and Deterministic connectomes. +%% (3.1) Find the common coordinates between the two connectomes. +% +% The two tractography method might have passed through slightly different +% white-matter voxels. Here we find the voxels where both models passed. We +% will compare the error only in these common voxels. There are more +% coordinates in the Prob connectome, because the tracking fills up more +% White-matter. +% +% So, hereafter: +% - First we find the indices in the probabilistic connectome of the +% coordinate in the deterministic connectome. But there are some of the +% coordinates in the Deterministic conectome that are NOT in the +% Probabilistic connectome. +% +% - Second we find the indices in the Deterministic connectome of the +% subset of coordinates in the Probabilistic connectome found in the +% previous step. +% +% - Third we find the common voxels. These allow us to find the rmse for +% the same voxels. +fprintf('Finding common brain coordinates between P and D connectomes...\n') +prob.coordsIdx = ismember(p.coords,d.coords,'rows'); +prob.coords = p.coords(prob.coordsIdx,:); +det.coordsIdx = ismember(d.coords,prob.coords,'rows'); +det.coords = d.coords(det.coordsIdx,:); +prob.rmse = prob.rmse( prob.coordsIdx); +det.rmse = det.rmse( det.coordsIdx); +clear p d + +%% (3.2) Make a scatter plot of the RMSE of the two tractography models +fh(4) = scatterPlotRMSE(det,prob); + +%% (3.3) Compute the strength-of-evidence (S) and the Earth Movers Distance. +% Compare the RMSE of the two models using the Stregth-of-evidence and the +% Earth Movers Distance. +se = feComputeEvidence(prob.rmse,det.rmse); + +%% (3.4) Strength of evidence in favor of Probabilistic tractography. +% Plot the distributions of resampled mean RMSE +% used to compute the strength of evidence (S). +fh(5) = distributionPlotStrengthOfEvidence(se); + +%% (3.5) RMSE distributions for Probabilistic and Deterministic tractography. +% Compare the distributions using the Earth Movers Distance. +% Plot the distributions of RMSE for the two models and report the Earth +% Movers Distance between the distributions. +fh(6) = distributionPlotEarthMoversDistance(se); + +end + +% ---------- Local Plot Functions ----------- % +function [fh, rmse, rmsexv] = plotHistRMSE(info) +% Make a plot of the RMSE: +rmse = info.rmse; +rmsexv = info.rmsexv; + +figName = sprintf('%s - RMSE',info.tractography); +fh = mrvNewGraphWin(figName); +[y,x] = hist(rmse,50); +plot(x,y,'k-'); +hold on +[y,x] = hist(rmsexv,50); +plot(x,y,'r-'); +set(gca,'tickdir','out','fontsize',16,'box','off'); +title('Root-mean squared error distribution across voxels','fontsize',16); +ylabel('number of voxels','fontsize',16); +xlabel('rmse (scanner units)','fontsize',16); +legend({'RMSE fitted data set','RMSE cross-validated'},'fontsize',16); +end + +function [fh, R] = plotHistRrmse(info) +% Make a plot of the RMSE Ratio: + +R = info.rrmse; +figName = sprintf('%s - RMSE RATIO',info.tractography); +fh = mrvNewGraphWin(figName); +[y,x] = hist(R,linspace(.5,4,50)); +plot(x,y,'k-','linewidth',2); +hold on +plot([median(R) median(R)],[0 1200],'r-','linewidth',2); +plot([1 1],[0 1200],'k-'); +set(gca,'tickdir','out','fontsize',16,'box','off'); +title('Root-mean squared error ratio','fontsize',16); +ylabel('number of voxels','fontsize',16); +xlabel('R_{rmse}','fontsize',16); +legend({sprintf('Distribution of R_{rmse}'),sprintf('Median R_{rmse}')}); +end + +function [fh, w] = plotHistWeights(info) +% Make a plot of the weights: + +w = info.w; +figName = sprintf('%s - Distribution of fascicle weights',info.tractography); +fh = mrvNewGraphWin(figName); +[y,x] = hist(w( w > 0 ),logspace(-5,-.3,40)); +semilogx(x,y,'k-','linewidth',2) +set(gca,'tickdir','out','fontsize',16,'box','off') +title( ... + sprintf('Number of fascicles candidate connectome: %2.0f\nNumber of fascicles in optimized connetome: %2.0f' ... + ,length(w),sum(w > 0)),'fontsize',16) +ylabel('Number of fascicles','fontsize',16) +xlabel('Fascicle weight','fontsize',16) +end + +function fh = scatterPlotRMSE(det,prob) +figNameRmse = sprintf('prob_vs_det_rmse_common_voxels_map'); +fh = mrvNewGraphWin(figNameRmse); +[ymap,x] = hist3([det.rmse;prob.rmse]',{[10:1:70], [10:1:70]}); +ymap = ymap./length(prob.rmse); +sh = imagesc(flipud(log10(ymap))); +cm = colormap(flipud(hot)); view(0,90); +axis('square') +set(gca, ... + 'xlim',[1 length(x{1})],... + 'ylim',[1 length(x{1})], ... + 'ytick',[1 (length(x{1})/2) length(x{1})], ... + 'xtick',[1 (length(x{1})/2) length(x{1})], ... + 'yticklabel',[x{1}(end) x{1}(round(end/2)) x{1}(1)], ... + 'xticklabel',[x{1}(1) x{1}(round(end/2)) x{1}(end)], ... + 'tickdir','out','ticklen',[.025 .05],'box','off', ... + 'fontsize',16,'visible','on') +hold on +plot3([1 length(x{1})],[length(x{1}) 1],[max(ymap(:)) max(ymap(:))],'k-','linewidth',1) +ylabel('Deterministic_{rmse}','fontsize',16) +xlabel('Probabilistic_{rmse}','fontsize',16) +cb = colorbar; +tck = get(cb,'ytick'); +set(cb,'yTick',[min(tck) mean(tck) max(tck)], ... + 'yTickLabel',round(1000*10.^[min(tck),... + mean(tck), ... + max(tck)])/1000, ... + 'tickdir','out','ticklen',[.025 .05],'box','on', ... + 'fontsize',16,'visible','on') +end + +function fh = distributionPlotStrengthOfEvidence(se) + +y_e = se.s.unlesioned_e; +ywo_e = se.s.lesioned_e; +dprime = se.s.mean; +std_dprime = se.s.std; +xhis = se.s.unlesioned.xbins; +woxhis = se.s.lesioned.xbins; + +histcolor{1} = [0 0 0]; +histcolor{2} = [.95 .6 .5]; +figName = sprintf('Strength_of_Evidence_test_PROB_vs_DET_model_rmse_mean_HIST'); +fh = mrvNewGraphWin(figName); +patch([xhis,xhis],y_e(:),histcolor{1},'FaceColor',histcolor{1},'EdgeColor',histcolor{1}); +hold on +patch([woxhis,woxhis],ywo_e(:),histcolor{2},'FaceColor',histcolor{2},'EdgeColor',histcolor{2}); +set(gca,'tickdir','out', ... + 'box','off', ... + 'ticklen',[.025 .05], ... + 'ylim',[0 .2], ... + 'xlim',[min(xhis) max(woxhis)], ... + 'xtick',[min(xhis) round(mean([xhis, woxhis])) max(woxhis)], ... + 'ytick',[0 .1 .2], ... + 'fontsize',16) +ylabel('Probability','fontsize',16) +xlabel('rmse','fontsize',16') + +title(sprintf('Strength of evidence:\n mean %2.3f - std %2.3f',dprime,std_dprime), ... + 'FontSize',16) +legend({'Probabilistic','Deterministic'}) +end + +function fh = distributionPlotEarthMoversDistance(se) + +prob = se.nolesion; +det = se.lesion; +em = se.em; + +histcolor{1} = [0 0 0]; +histcolor{2} = [.95 .6 .5]; +figName = sprintf('EMD_PROB_DET_model_rmse_mean_HIST'); +fh = mrvNewGraphWin(figName); +plot(prob.xhist,prob.hist,'r-','color',histcolor{1},'linewidth',4); +hold on +plot(det.xhist,det.hist,'r-','color',histcolor{2},'linewidth',4); +set(gca,'tickdir','out', ... + 'box','off', ... + 'ticklen',[.025 .05], ... + 'ylim',[0 .12], ... + 'xlim',[0 95], ... + 'xtick',[0 45 90], ... + 'ytick',[0 .06 .12], ... + 'fontsize',16) +ylabel('Proportion white-matter volume','fontsize',16) +xlabel('RMSE (raw MRI scanner units)','fontsize',16') +title(sprintf('Earth Movers Distance: %2.3f (raw scanner units)',em.mean),'FontSize',16) +legend({'Probabilistic','Deterministic'}) +end + diff --git a/utility/fefgGet.m b/utility/fefgGet.m new file mode 100755 index 0000000..89bd940 --- /dev/null +++ b/utility/fefgGet.m @@ -0,0 +1,813 @@ +function val = fefgGet(fg,param,varargin) +% Get values from a fiber group structure +% +% val = fefgGet(fg,param,varargin) +% +% Copyright (2015), Franco Pestilli (Indiana Univ.) - Cesar F. Caiafa (CONICET) +% email: pestillifranco@gmail.com and ccaiafa@gmail.com +% +%------------ +% Returns the length of each fiber in the fiber group +% flen = fefgGet(fg,'length') +%------------ +% Compute the Westin shape parameters (linearity and planarity) +% for all the fibers in the fiber group. +% Requires a dt structure. +% westin = fefgGet(fg,'westinshape',dt) +% westin = fefgGet(fg,'westinshape',eigenvals) +% westin = fefgGet(fg,'westinshape',dtFileName) +%------------- +% Compute eigenvalues for the fibers in a fiber group. +% It requires a dt structure. +% eigenvals = fefgGet(fg,'eigenvals',dt) +% eigenvals = fefgGet(fg,'eigenvals',dtFileName) +%------------- +% Compute the 6 parameters for the tensors at each node in each fiber. +% It requires a dt structure. +% dt6 = fefgGet(fg,'eigenvals',dt) +% dt6 = fefgGet(fg,'eigenvals',dtFileName) +%------------- +% Compute the radial and axial ADC for all the fibers in the fiber group. +% Requires a dt structure. +% adc = fefgGet(fg,'adc',dt) +% adc = fefgGet(fg,'adc',eigenvals) +% adc = fefgGet(fg,'adc',dtFileName) +%------------- +% Compute the FA for all the fibers in the fiber group. +% Requires a dt structure. +% fa = fefgGet(fg,'fa',dt) +% fa = fefgGet(fg,'fa',eigenvals) +% fa = fefgGet(fg,'fa',dtFileName) +%------------- +% Compute the Mean Diffusivity for all the fibers in the fiber group. +% Requires a dt structure. +% md = fefgGet(fg,'md',dt) +% md = fefgGet(fg,'md',eigenvals) +% md = fefgGet(fg,'md',dtFileName) +%------------- +% Compute the Radial Diffusivity for all the fibers in the fiber group. +% Requires a dt structure. +% rd = fefgGet(fg,'rd',dt) +% rd = fefgGet(fg,'rd',eigenvals) +% rd = fefgGet(fg,'rd',dtFileName) +%------------- +% Compute the Axial Diffusivity for all the fibers in the fiber group. +% Requires a dt structure. +% ad = fefgGet(fg,'ad',dt) +% ad = fefgGet(fg,'ad',eigenvals) +% ad = fefgGet(fg,'ad',dtFileName) +%------------- +% Compute the radial and axial ADC for all the fibers in the fiber group. +% Requires a dt structure. +% adc = fefgGet(fg,'adc',dt) +% adc = fefgGet(fg,'adc',eigenvals) +% adc = fefgGet(fg,'adc',dtFileName) +%------------- +% +% Parameters +% General +% 'name' +% 'type' +% 'colorrgb' +% 'thickness' +% 'visible' +% +% Fiber related +% 'nfibers'- Number of fibers in this group +% 'nodes per fiber' - Number of nodes per fiber. +% 'fibers' - Fiber coordinates +% 'fibernames' +% 'fiberindex' +% Compute the Mean Diffusivity for all the fibers in the fiber group. +% Requires a dt structure. +% fa = fefgGet(fg,'fa',dt) +% fa = fefgGet(fg,'fa',eigenvals) +% +% ROI and image coord related +% 'unique image coords' +% 'nodes to imagecoords' - +% 'voxel2fiber node pairs' - For each roi coord, an Nx2 matrix of +% (fiber number,node number) +% 'nodes in voxels' - Nodes inside the voxels of roi coords +% 'voxels in fg' - Cell array of the roiCoords touched by each fiber +% 'voxels2fibermatrix' - Binary matrix (voxels by fibers). 1s when a +% fiber is in a voxel of the roiCoords (which are, sadly, implicit). +% +% Tensor and tractography related +% 'tensors' - Tensors for each node +% +% +% See also: fgCreate; fgSet +% +% Copyright (2013-2014), Franco Pestilli, Stanford University, pestillifranco@gmail.com. +val = []; + +switch strrep(lower(param),' ','') + + % Basic fiber parameters + case 'name' + val = fg.name; + case 'type' % Should always be fibergroup + val = fg.type; + + % Fiber visualization settings. + case 'colorrgb' + val = fg.colorRgb; + case 'thickness' + val = fg.thickness; + case 'visible' + val = fg.visible; + + % Simple fiber properties -- + case {'fibers'} + % val = fefgGet(fg,'fibers',fList); + % + % Returns a 3xN matrix of fiber coordinates corresponding to the + % fibers specified in the integer vector, fList. This differs from + % the dtiH (mrDiffusion) representation, where fiber coordinates + % are stored as a set of cell arrays for each fiber. + if ~isempty(varargin) + list = varargin{1}; + val = cell(length(list),1); + for ii=1:length(list) + val{ii} = fg.fibers{ii}; + end + else + val = fg.fibers; + end + case 'fibernames' + val = fg.fiberNames; + case 'fiberindex' + val = fg.fiberIndex; + case 'nfibers' + val = length(fg.fibers); + case {'nodesperfiber','nsamplesperfiber','nfibersamples'} + % fefgGet(fg,'n samples per fiber ') + % How many samples per fiber. This is about equal to + % their length in mm, though we need to write the fiber lengths + % routine to actually calculate this. + nFibers = fefgGet(fg,'n fibers'); + val = zeros(1,nFibers); + for ii=1:nFibers + val(ii) = length(fg.fibers{ii}); + end + + % Fiber group (subgroup) properties. + % These are used when we classify fibers into subgroups. We should + % probably clean up this organization which is currently + % + % subgroup - length of fibers, an index of group identity + % subgroupNames() + % .subgroupIndex - Probably should go away and the index should + % just be + % .subgroupName - Probably should be moved up. + % + case {'ngroups','nsubgroups'} + val = length(fg.subgroupNames); + case {'groupnames'} + val = cell(1,fefgGet(fg,'n groups')); + for ii=1:nGroups + val{ii} = fg.subgroupNames(ii).subgroupName; + end + + % DTI properties + case 'tensors' + val = fg.tensors; + + % Fiber to coord calculations + case {'imagecoords'} + % c = fefgGet(fgAcpc,'image coords',fgList,xForm); + % c = fefgGet(fgAcpc,'image coords',fgList,xForm); + % + % Return the image coordinates of a specified list of fibers + % Returns a matrix that is fgList by 3 of the image coordinates for + % each node of each fiber. + % + % Fiber coords are represented at fine resolution in ACPC space. + % These coordinates are rounded and in image space + if ~isempty(varargin) + fList = varargin{1}; + if length(varargin) > 1 + xForm = varargin{2}; + % Put the fiber coordinates into image space + fg = dtiXformFiberCoords(fg,xForm); + end + else + % In this case, the fiber coords should already be in image + % space. + nFibers = fefgGet(fg,'n fibers'); + fList = 1:nFibers; + end + + % Pull out the coordinates and ceil them. These are in image + % space. + nFibers = length(fList); + val = cell(1,nFibers); + if nFibers == 1 + val = ceil(fg.fibers{fList(1)}')+1; + + else + feOpenLocalCluster + parfor ii=1:nFibers + val{ii} = ceil(fg.fibers{fList(ii)}')+1; + end + end + + case {'uniqueimagecoords'} + % coords = fefgGet(fgIMG,'unique image coords'); + % + % The fg input must be in IMG space. + % + % Returns the unique image coordinates of all the fibers as an Nx3 + % matrix of integers. + % val = round(horzcat(fg.fibers{:})'); + val = ceil(horzcat(fg.fibers{:})')+1; + val = unique(val,'rows'); + + case {'allimagecoords'} + % coords = fefgGet(fgIMG,'all image coords'); + % + % The fg input must be in IMG space. + % + % Returns all image coordinates of all the fibers as an Nx3 + % matrix of integers. + % val = round(horzcat(fg.fibers{:})'); + val = ceil(horzcat(fg.fibers{:})')+1; + + case {'uniqueacpccoords'} + % coords = fefgGet(fg,'unique acpc coords'); + % + % The fg input must be in ACPC space. + % + % Returns the unique ACPC coordinates of all the fibers as an Nx3 + % matrix of integers. + val = fefgGet(fg, 'uniqueimagecoords') ; + + case {'nodes2voxels'} + % nodes2voxels = fefgGet(fgImg,'nodes2voxels',roiCoords) + % + % The roiCoords are a matrix of Nx3 coordinates. They describe a + % region of interest, typically in image space or possibly in acpc + % space. + % + % We return a cell array that is a mapping of fiber nodes to voxels in + % the roi. The roi is specified as an Nx3 matrix of coordinates. + % The returned cell array, nodes2voxels, has the same number of + % cells as there are fibers. + % + % Unlike the fiber group cells, which have a 3D coordinate of each + % node, this cell array has an integer that indexes the row of + % roiCoords that contains the node. If a node is not in any of the + % roiCoords, the entry in node2voxels{ii} for that node is zero. + % This means that node is outside the 'roiCoords'. + % + % Once again: The cell nodes2voxels{ii} specifies whether each + % node in the iith fiber is inside a voxel in the roiCoords. The + % value specifies the row in roiCoords that contains the node. + % + if isempty(varargin), error('roiCoords required'); + else + roiCoords = varargin{1}; + end + fprintf('[%s] Computing nodes-to-voxels..',mfilename) + + % Find the roiCoord for each node in each fiber. + nFiber = fefgGet(fg,'n fibers'); + val = cell(nFiber,1); + + feOpenLocalCluster + parfor ii=1:nFiber + % if ~mod(ii,200), fprintf('%d ',ii); end + % Node coordinates in image space + nodeCoords = fefgGet(fg,'image coords',ii); + + % The values in loc are the row of the coords matrix that contains + % that sample point in a fiber. For example, if the number 100 is + % in the 10th position of loc, then the 10th sample point in the + % fiber passes through the voxel in row 100 of coords. + %keyboard + [~, val{ii}] = ismember(nodeCoords, roiCoords, 'rows'); % This operation is slow. + end + fprintf(' took: %2.3fminutes.\n',toc/60) + + case {'voxel2fibernodepairs','v2fn'} + % voxel2FNpairs = fefgGet(fgImg,'voxel 2 fibernode pairs',roiCoords); + % voxel2FNpairs = fefgGet(fgImg,'voxel 2 fibernode pairs',roiCoords,nodes2voxels); + % + % The return is a cell array whose size is the number of voxels. + % The cell is a Nx2 matrix of the (fiber, node) pairs that pass + % through it. + % + % The value N is the number of nodes in the voxel. The first + % column is the fiber number. The second column reports the indexes + % of the nodes for each fiber in each voxel. + fprintf('[%s] Computing fibers/nodes pairing in each voxel..\n',mfilename) + + if (length(varargin) < 1), error('Requires the roiCoords.'); + else + roiCoords = varargin{1}; + nCoords = size(roiCoords,1); + end + if length(varargin) < 2 + % We assume the fg and the ROI coordinates are in the same + % coordinate frame. The following line gives the list of fibers + % containing only the nodes that are included in the ROI + tic,nodes2voxels = fefgGet(fg,'nodes 2 voxels',roiCoords); + else nodes2voxels = varargin{2}; + end + + nFibers = fefgGet(fg,'nFibers'); + voxelsInFG = fefgGet(fg,'voxels in fg',nodes2voxels); + + tic,roiNodesInFG = fefgGet(fg,'nodes in voxels',nodes2voxels); + tic, val = cell(1,nCoords); + for thisFiber=1:nFibers + voxelsInFiber = voxelsInFG{thisFiber}; % A few voxels, in a list + nodesInFiber = roiNodesInFG{thisFiber}; % The corresponding nodes + + % Then add a row for each (fiber,node) pairs that pass through + % the voxels for this fiber. + for jj=1:length(voxelsInFiber) + thisVoxel = voxelsInFiber(jj); + % Print out roi coord and fiber coord to verify match + % roiCoords(thisVoxel,:) + % fg.fibers{thisFiber}(:,nodesInFiber(jj)) + % Would horzcat be faster? + val{thisVoxel} = cat(1,val{thisVoxel},[thisFiber,nodesInFiber(jj)]); + end + end + fprintf('[%s] fiber/node pairing completed in: %2.3fs.\n',mfilename, toc) + + case {'voxel2fibers','fiberdensity'} + % voxel2FNpairs = fefgGet(fgImg,'fiber density',roiCoords); + % + % The return is a cell array whose size is the number of voxels. + % The cell is a Nx1 matrix of fiber counts. How many fibers in each + % voxel. + % + fprintf('[%s] Computing fiber density in each voxel...\n',mfilename) + + if (length(varargin) < 1), + roiCoords = fefgGet(fg,'uniqueimagecoords'); + fprintf('[%s] Computing white-matter volume ROI from fibers coordinates.\n',mfilename) + fprintf(' Assuming fiber coordinates in IMG space.\n') + else + roiCoords = varargin{1}; + end + + if length(varargin) < 2 + % We assume the fg and the ROI coordinates are in the same + % coordinate frame. + tic,nodes2voxels= fefgGet(fg,'nodes 2 voxels',roiCoords); + else nodes2voxels = varargin{2}; + end + + nCoords = size(roiCoords,1); + nFibers = fefgGet(fg,'nFibers'); + voxelsInFG = fefgGet(fg,'voxels in fg',nodes2voxels); + + tic, fibersInVox = cell(1,nCoords); + for thisFiber=1:nFibers + voxelsInFiber = voxelsInFG{thisFiber}; % A few voxels, in a list + + % Then add a row for each (fiber,node) pairs that pass through + % the voxels for this fiber. + for jj=1:length(voxelsInFiber) + thisVoxel = voxelsInFiber(jj); + % Print out roi coord and fiber coord to verify match + % roiCoords(thisVoxel,:) + % fg.fibers{thisFiber}(:,nodesInFiber(jj)) + % Would horzcat be faster? + fibersInVox{thisVoxel} = cat(1,fibersInVox{thisVoxel},thisFiber); + end + end + + % Now create the fiber density, the unique fibers in each voxel + val = zeros(length(fibersInVox),1); + for ivx = 1:length(fibersInVox) + val(ivx) = length(unique(fibersInVox{ivx})); + end + + fprintf('[%s] fiber density completed in: %2.3fs.\n',mfilename, toc) + + case {'uniquefibersinvox'} + % uniquefvx = fefgGet(fgImg,'uniquefibrsinvox',roiCoords); + % + % The return is a vector whose size is the number of voxels containing + % the unique fibers in each voxel + % + fprintf('[%s] Computing the unique fibers in each voxel...\n',mfilename) + tic + if (length(varargin) < 1), error('Requires the roiCoords.'); + else + roiCoords = varargin{1}; + nCoords = size(roiCoords,1); + end + + % We assume the fg and the ROI coordinates are in the same + % coordinate frame. + nodes2voxels = fefgGet(fg,'nodes 2 voxels',roiCoords); + + nFibers = fefgGet(fg,'nFibers'); + voxelsInFG = fefgGet(fg,'voxels in fg',nodes2voxels); + + fibersInVox = cell(1,nCoords); + for thisFiber=1:nFibers + voxelsInFiber = voxelsInFG{thisFiber}; % A few voxels, in a list + + % Then add a row for each (fiber,node) pairs that pass through + % the voxels for this fiber. + if ~isempty(voxelsInFiber) + for jj=1:length(voxelsInFiber) + thisVoxel = voxelsInFiber(jj); + fibersInVox{thisVoxel} = cat(1,fibersInVox{thisVoxel},thisFiber); + end + end + end + + % Now create find the unique fibers in each voxel + val = cell(length(fibersInVox),1); + for ivx = 1:length(fibersInVox) + val{ivx} = (unique(fibersInVox{ivx})); + end + fprintf('[%s] done computing unique fibers in each voxel: %2.3fs.\n',mfilename, toc) + + case {'nodesinvoxels'} + % nodesInVoxels = fefgGet(fg,'nodes in voxels',nodes2voxels); + % + % This cell array is a modified form of nodes2voxels (see above). + % In that cell array every node in every fiber has a number + % referring to its row in roiCoords, or a 0 when the node is not in + % any roiCoord voxel. + % + % This cell array differs only in that the 0s removed. This + % is used to simplify certain calculations. + % + if (length(varargin) <1), error('Requires nodes2voxels cell array.'); end + tic,fprintf('[%s] Computing nodes-in-voxels..',mfilename) + nodes2voxels = varargin{1}; + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + + feOpenLocalCluster + % For each fiber, this is a list of the nodes that pass through + % a voxel in the roiCoords + parfor ii = 1:nFibers + % For each fiber, this is a list of the nodes that pass through + % a voxel in the roiCoords + lst = (nodes2voxels{ii} ~= 0); + val{ii} = find(lst); + end + fprintf(' took: %2.3fs.\n',toc) + + case 'voxelsinfg' + % voxelsInFG = fefgGet(fgImg,'voxels in fg',nodes2voxels); + % + % A cell array length n-fibers. Each cell has a list of the voxels + % (rows of roiCoords) for a fiber. + % + % This routine eliminates the 0's in the nodes2voxels lists. + % + if length(varargin) < 1, error('Requires nodes2voxels cell array.'); end + tic,fprintf('[%s] Computing voxels-in-fg..',mfilename) + + nodes2voxels = varargin{1}; + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + + feOpenLocalCluster + parfor ii = 1:nFibers + % These are the nodes that pass through a voxel in the + % roiCoords + lst = (nodes2voxels{ii} ~= 0); + val{ii} = nodes2voxels{ii}(lst); + end + fprintf(' took: %2.3fs.\n',toc) + + case {'voxels2fibermatrix','v2fm'} + % v2fm = fefgGet(fgImg,'voxels 2 fiber matrix',roiCoords); + % Or, + % v2fnPairs = fefgGet(fgImg,'v2fn',roiCoords); + % v2fm = fefgGet(fgImg,'voxels 2 fiber matrix',roiCoords, v2fnPairs); + % + % mrvNewGraphWin; imagesc(v2fm) + % + % Returns a binary matrix of size Voxels by Fibers. + % When voxel ii has at least one node from fiber jj, there is a one + % in v2fm(ii,jj). Otherwise, the entry is zero. + % + + % Check that the fg is in the image coordspace: + if isfield(fg, 'coordspace') && ~strcmp(fg.coordspace, 'img') + error('Fiber group is not in the image coordspace, please xform'); + end + + if isempty(varargin), error('roiCoords required'); + else + roiCoords = varargin{1}; + nCoords = size(roiCoords,1); + if length(varargin) < 2 + v2fnPairs = fefgGet(fg,'v2fn',roiCoords); + else + v2fnPairs = varargin{2}; + end + end + + % Allocate matrix of voxels by fibers + val = zeros(nCoords,fefgGet(fg,'n fibers')); + + % For each coordinate, find the fibers. Set those entries to 1. + for ii=1:nCoords + if ~isempty(v2fnPairs{ii}) + f = unique(v2fnPairs{ii}(:,1)); + end + val(ii,f) = 1; + end + + case {'fibersinroi','fginvoxels','fibersinvoxels'} + % fList = fefgGet(fgImg,'fibersinroi',roiCoords); + % + % v2fn = fefgGet(fgImg,'v2fn',roiCoords); + % fList = fefgGet(fgImg,'fibersinroi',roiCoords,v2fn); + % + % Returns an integer vector of the fibers with at least + % one node in a region of interest. + % + % The fg and roiCoords should be in the same coordinate frame. + % + if isempty(varargin), error('roiCoords required'); + elseif length(varargin) == 1 + roiCoords = varargin{1}; + v2fnPairs = fefgGet(fg,'v2fn',roiCoords); + elseif length(varargin) > 1 + roiCoords = varargin{1}; + v2fnPairs = varargin{2}; + end + + val = []; nCoords = size(roiCoords,1); + for ii=1:nCoords + if ~isempty(v2fnPairs{ii}) + val = cat(1,val,v2fnPairs{ii}(:,1)); + end + end + val = sort(unique(val),'ascend'); + + case {'coordspace','fibercoordinatespace','fcspace'} + % In some cases, the fg might contain information telling us in which + % coordinate space its coordinates are set. This information is set + % as a struct. Each entry in the struct can be either a 4x4 xform + % matrix from the fiber coordinates to that space (with eye(4) for + % the space in which the coordinates are defined), or (if the xform + % is not know) an empty matrix. + + cspace_fields = fields(fg.coordspace); + val = []; + for f=1:length(cspace_fields) + this_field = cspace_fields{f}; + if isequal(getfield(fg.coordspace, this_field), eye(4)) + val = this_field; + end + end + + case {'length'} + % Returns the length of each fiber in the fiber group + % flen = fefgGet(fg,'length') + + % Measure the step size of the first fiber. They *should* all be the same! + stepSize = mean(sqrt(sum(diff(fg.fibers{1},1,2).^2))); + + % Check that they are + %stepSize2 = mean(sqrt(sum(diff(fg.fibers{2},1,2).^2))); + %assertElementsAlmostEqual(stepSize,stepSize2,'relative',.001,.001); + + % Estimate the length for the fibers, as well mean, min and max + val = cellfun('length',fg.fibers)*stepSize; + + case {'dt6'} + % Compute the 6 parameters for the tensors at each node in each fiber. + % It requires a dt structure. + % dt6 = fefgGet(fg,'dt6',dt) + % dt6 = fefgGet(fg,'dt6',dtFileName) + + if ~ischar(varargin{1}) + if isstruct(varargin{1}) + % A dti structure was passed. + dt = varargin{1}; + else + error('[%s] A ''dt'' structure is necessary.', mfilename) + end + else % The string should be a path to a dt.mat file. + dt = dtiLoadDt6(varargin{1}); + end + + % Get the dt6 tensors for each node in each fiber. + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + xform = inv(dt.xformToAcpc); + dt6 = dt.dt6; clear dt + feOpenLocalCluster + parfor ii = 1:nFibers + % Get the fiber coordinates. + coords = fg.fibers{ii}'; % Assumed in ACPC + + [val1,val2,val3,val4,val5,val6] = ... + dtiGetValFromTensors(dt6, coords, xform,'dt6','nearest'); + + % Build a vector of tesnsors' eigenvalues + val{ii} = [val1,val2,val3,val4,val5,val6]; + end + + + case {'eigenvals'} + % Compute eigenvalues for the fibers in a fiber group. + % It requires a dt structure. + % eigenvals = fefgGet(fg,'eigenvals',dt) + % eigenvals = fefgGet(fg,'eigenvals',dt6FileName) + if ~ischar(varargin{1}) + if ( ~isstruct(varargin{1}) ) + dt6 = fefgGet(fg,'dt6',varargin{1}); + elseif ( size(varargin{1},1)==6 ) + dt6 = varargin{1}; + else + error('[%s] Either a ''dt'' structure or a ''dt6'' vector of tensor coefficients is necessary.\n',mfilename) + end + else % The string should be a path to a dt6.mat file. + dt6 = fefgGet(fg,'dt6',dtiLoadDt6(varargin{1})); + end + + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + + feOpenLocalCluster + parfor ii = 1:nFibers + + % We now have the dt6 data from all of the fibers. We extract the + % directions into vec and the eigenvalues into val. The units of val are + % um^2/sec or um^2/msec .. somebody answer this here, please. + [~,val{ii}] = dtiEig(dt6{ii}); + end + + for ii = 1:nFibers + % Some of the ellipsoid fits are wrong and we get negative eigenvalues. + % These are annoying. If they are just a little less than 0, then clipping + % to 0 is not an entirely unreasonable thing. Maybe we should check for the + % magnitude of the error? + nonPD = find(any(val{ii}<0,2), 1); + if(~isempty(nonPD)) + %fprintf('\n NOTE: %d fiber points had negative eigenvalues. These will be clipped to 0..\n',length(nonPD)); + val{ii}(val{ii}<0) = 0; + end + + threeZeroVals = (sum(val{ii}, 2) == 0); + %if ~isempty (threeZeroVals) + % fprintf('\n NOTE: %d of these fiber points had all three negative eigenvalues. These will be excluded from analyses\n', length(threeZeroVals)); + %end + val{ii}(threeZeroVals, :)=[]; + end + + case {'fa'} + % Compute the FA for all the fibers in the fiber group. + % Requires a dt structure. + % fa = fefgGet(fg,'fa',dt) + % fa = fefgGet(fg,'fa',eigenvals) + % fa = fefgGet(fg,'fa',dtFileName) + if (~isstruct(varargin{1}) || ischar(varargin{1})) && ~iscell(varargin{1}) + % A dti structue was passed. + eigenvals = fefgGet(fg,'eigenvals',varargin{1}); + else + % We assume that eigenvals were passed already + eigenvals = varargin{1}; + end + + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + + feOpenLocalCluster + parfor ii = 1:nFibers + [val{ii},~,~,~] = dtiComputeFA(eigenvals{ii}); + end + + case {'md'} + % Compute the Mean Diffusivity for all the fibers in the fiber group. + % Requires a dt structure. + % md = fefgGet(fg,'md',dt) + % md = fefgGet(fg,'md',eigenvals) + % md = fefgGet(fg,'md',dtFileName) + + if (~isstruct(varargin{1}) || ischar(varargin{1})) && ~iscell(varargin{1}) + % A dti structue was passed. + eigenvals = fefgGet(fg,'eigenvals',varargin{1}); + else + % We assume that eigenvals were passed already + eigenvals = varargin{1}; + end + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + + feOpenLocalCluster + parfor ii = 1:nFibers + [~,val{ii},~,~] = dtiComputeFA(eigenvals{ii}); + end + + case {'ad'} + % Compute the Axial Diffusivity for all the fibers in the fiber group. + % Requires a dt structure. + % ad = fefgGet(fg,'ad',dt) + % ad = fefgGet(fg,'ad',eigenvals) + % ad = fefgGet(fg,'ad',dtFileName) + + if (~isstruct(varargin{1}) || ischar(varargin{1})) && ~iscell(varargin{1}) + % A dti structue was passed. + eigenvals = fefgGet(fg,'eigenvals',varargin{1}); + else + % We assume that eigenvals were passed already + eigenvals = varargin{1}; + end + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + + feOpenLocalCluster + parfor ii = 1:nFibers + [~,~,~,val{ii}] = dtiComputeFA(eigenvals{ii}); + end + + case {'rd'} + % Compute the Radial Diffusivity for all the fibers in the fiber group. + % Requires a dt structure. + % rd = fefgGet(fg,'rd',dt) + % rd = fefgGet(fg,'rd',eigenvals) + % rd = fefgGet(fg,'rd',dtFileName) + + if (~isstruct(varargin{1}) || ischar(varargin{1})) && ~iscell(varargin{1}) + % A dti structue was passed. + eigenvals = fefgGet(fg,'eigenvals',varargin{1}); + else + % We assume that eigenvals were passed already + eigenvals = varargin{1}; + end + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + + feOpenLocalCluster + parfor ii = 1:nFibers + [~,~,val{ii},~] = dtiComputeFA(eigenvals{ii}); + end + + case {'adc'} + % Compute the radial and axial ADC for all the fibers in the fiber group. + % Requires a dt structure. + % adc = fefgGet(fg,'adc',dt) + % adc = fefgGet(fg,'adc',eigenvals) + % adc = fefgGet(fg,'adc',dtFileName) + + if (~isstruct(varargin{1}) || ischar(varargin{1})) && ~iscell(varargin{1}) + % A dti structue was passed. + eigenvals = fefgGet(fg,'eigenvals',varargin{1}); + else + % We assume that eigenvals were passed already + eigenvals = varargin{1}; + end + + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + feOpenLocalCluster + parfor ii = 1:nFibers + [~,~,val{ii}.radial, val{ii}.axial] = dtiComputeFA(eigenvals{ii}); + end + + case {'westinshape'} + % Compute the Westin shape parameters (linearity and planarity) + % for all the fibers in the fiber group. + % Requires a dt structure. + % westin = fefgGet(fg,'westinshape',dt) + % westin = fefgGet(fg,'westinshape',eigenvals) + % westin = fefgGet(fg,'westinshape',dtFileName) + + if (~isstruct(varargin{1}) || ischar(varargin{1})) && ~iscell(varargin{1}) + % A dt structue was passed. + eigenvals = fefgGet(fg,'eigenvals',varargin{1}); + else + % We assume that eigenvals were passed already + eigenvals = varargin{1}; + end + + % This was the originial formulation described in: + % C-F. Westin, S. Peled, H. Gubbjartsson, R. Kikinis, and F.A. Jolesz. + % Geometrical diffusion measures for MRI from tensor basis analysis. + % In Proceedings 5th Annual ISMRM, 1997. + nFibers = fefgGet(fg,'nFibers'); + val = cell(1,nFibers); + + feOpenLocalCluster + parfor ii = 1:nFibers + [val{ii}.linearity, val{ii}.planarity] = dtiComputeWestinShapes(eigenvals{ii}); + end + + case 'ntotalnodes' + val = size(horzcat(fg.fibers{:}),2); + + otherwise + error('Unknown fg parameter: "%s"\n',param); +end + +return