├── subprojects ├── lapack-d.wrap ├── mir-blas.wrap ├── mir-core.wrap ├── cblas-d.wrap └── mir-algorithm.wrap ├── examples └── gesv │ ├── .gitignore │ ├── meson.build │ ├── dub.sdl │ └── source │ └── app.d ├── .gitignore ├── .circleci └── config.yml ├── index.d ├── README.md ├── .travis.yml ├── dub.sdl ├── meson.build └── source └── mir └── lapack.d /subprojects/lapack-d.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | directory=lapack-d 3 | url=https://github.com/libmir/lapack.git 4 | revision=head -------------------------------------------------------------------------------- /subprojects/mir-blas.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | directory=mir-blas 3 | url=https://github.com/libmir/mir-blas.git 4 | revision=head -------------------------------------------------------------------------------- /subprojects/mir-core.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | directory=mir-core 3 | url=https://github.com/libmir/mir-core.git 4 | revision=head -------------------------------------------------------------------------------- /subprojects/cblas-d.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | directory=cblas-d 3 | url=https://github.com/DlangScience/cblas.git 4 | revision=head -------------------------------------------------------------------------------- /subprojects/mir-algorithm.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | directory=mir-algorithm 3 | url=https://github.com/libmir/mir-algorithm.git 4 | revision=head -------------------------------------------------------------------------------- /examples/gesv/.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | docs.json 3 | __dummy.html 4 | docs/ 5 | gesvex.so 6 | gesvex.dylib 7 | gesvex.dll 8 | gesvex.a 9 | gesvex.lib 10 | gesvex-test-* 11 | gesvex 12 | *.exe 13 | *.o 14 | *.obj 15 | *.lst 16 | -------------------------------------------------------------------------------- /examples/gesv/meson.build: -------------------------------------------------------------------------------- 1 | mir_gesv_example_exe = executable(meson.project_name() + '-example', 2 | ['source/app.d'], 3 | include_directories: directories, 4 | dependencies: this_dep, 5 | ) 6 | 7 | test(meson.project_name() + '-example', mir_gesv_example_exe) 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | docs.json 3 | __dummy.html 4 | *.o 5 | *.obj 6 | __test__*__ 7 | 8 | *.sublime-project 9 | 10 | example/example 11 | 12 | dub.selections.json 13 | mir-lapack-test-library 14 | *.sublime-workspace 15 | .vscode 16 | *.DS_Store 17 | *.a 18 | mir-lapack-test-openblas 19 | examples/gesv/gesv 20 | *.lib 21 | *.dll 22 | build/ 23 | *.exe 24 | _build_dir_ 25 | subprojects/*/ 26 | *.pdb -------------------------------------------------------------------------------- /examples/gesv/dub.sdl: -------------------------------------------------------------------------------- 1 | name "gesv" 2 | authors "Ilya Yaroshenko" 3 | description "GESV example" 4 | copyright "Copyright © 2018, Ilya Yaroshenko" 5 | license "BSL-1.0" 6 | dependency "mir-lapack" path="../../" 7 | 8 | configuration "application" { 9 | targetType "executable" 10 | } 11 | 12 | configuration "travis" { 13 | targetType "executable" 14 | subConfiguration "mir-lapack" "blas" # for Travis, because it has deprecated openblas 15 | } 16 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | mirci: libmir/upload_docs@0.1.4 5 | 6 | workflows: 7 | version: 2 8 | build-deploy: 9 | jobs: 10 | - mirci/test_and_build_docs: 11 | filters: 12 | tags: 13 | only: /^v(\d)+(\.(\d)+)+$/ 14 | - mirci/upload_docs: 15 | to: mir-lapack.libmir.org 16 | requires: 17 | - mirci/test_and_build_docs 18 | filters: 19 | branches: 20 | ignore: /.*/ 21 | tags: 22 | only: /^v(\d)+(\.(\d)+)+$/ 23 | -------------------------------------------------------------------------------- /index.d: -------------------------------------------------------------------------------- 1 | Ddoc 2 | 3 | $(P ndslice wrapper for LAPACK) 4 | 5 | $(P The following table is a quick reference guide for which Mir LAPACK modules to 6 | use for a given category of functionality.) 7 | 8 | $(BOOKTABLE , 9 | $(TR 10 | $(TH Modules) 11 | $(TH Description) 12 | ) 13 | $(TR 14 | $(TDNW $(MREF mir,lapack)) 15 | $(TD ndslice wrapper for LAPACK) 16 | ) 17 | ) 18 | 19 | Copyright: Copyright © 2020-, Ilya Yaroshenko. 20 | 21 | Macros: 22 | TITLE=Mir LAPACK 23 | WIKI=Mir LAPACK 24 | DDOC_BLANKLINE= 25 | _= 26 | 34ref -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mir-lapack 2 | NDSLICE wrapper for LAPACK 3 | 4 | mir-lapack assumes that matrixes are passed in the transposed form. 5 | Each (contiguous) row in a mir's matrix should store a (contiguous) column of a Fortran matrix. 6 | 7 | ## Required system libraries 8 | 9 | See [wiki: Link with CBLAS & LAPACK](https://github.com/libmir/mir-lapack/wiki/Link-with-CBLAS-&-LAPACK). 10 | 11 | ## Wrapped API 12 | 13 | http://mir-lapack.libmir.org 14 | 15 | --------------- 16 | 17 | This work has been sponsored by [Symmetry Investments](http://symmetryinvestments.com) and [Kaleidic Associates](https://github.com/kaleidicassociates). 18 | 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: d 4 | 5 | d: 6 | - dmd 7 | - ldc 8 | 9 | addons: 10 | apt: 11 | packages: 12 | # - pkg-config 13 | - liblapack-dev 14 | - libblas-dev 15 | 16 | # install: 17 | # - pyenv global system 3.6 18 | # - pip3 install 'meson>=0.45' 19 | # - mkdir .ntmp 20 | # - curl -L https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip -o .ntmp/ninja-linux.zip 21 | # - unzip .ntmp/ninja-linux.zip -d .ntmp 22 | # before_script: 23 | # - export PATH=$PATH:$PWD/.ntmp 24 | 25 | script: 26 | - dub build --build=unittest -c blas 27 | - dub --root examples/gesv -c travis 28 | # - meson build -D with_test=true && cd build && ninja -j4 && ninja test -v && cd .. 29 | -------------------------------------------------------------------------------- /examples/gesv/source/app.d: -------------------------------------------------------------------------------- 1 | // betterC code style 2 | import mir.ndslice.slice: sliced; 3 | import mir.ndslice.topology: canonical; 4 | import mir.lapack: gesv, lapackint; 5 | 6 | // column major storage 7 | __gshared double[9] a = [ 8 | 1.0, 2, -1, 9 | -1.0, 2, 5, 10 | 1.0, -4, 0]; 11 | // ditto 12 | __gshared double[6] b = [ 13 | 2.0, -6, 9, 14 | 0 , -6, 1]; 15 | // ditto 16 | __gshared double[6] t = [ 17 | 1.0, 2, 3, 18 | -1.0, 0, 1]; 19 | 20 | __gshared lapackint[3] ipiv = [0, 0, 0]; 21 | 22 | // nothrow @nogc extern(C) 23 | int main() 24 | { 25 | // Canonical kind is required 26 | auto as = a[].sliced(3, 3).canonical; 27 | auto bs = b[].sliced(2, 3).canonical; 28 | auto ts = b[].sliced(2, 3).canonical; 29 | auto ipivs = ipiv[].sliced(3); 30 | 31 | // Solve systems of linear equations AX = B for X. 32 | // X stores in B 33 | auto info = gesv(as, ipivs, bs); 34 | 35 | if (info) 36 | return cast(int)(info << 1); 37 | 38 | // Check result 39 | if (bs != ts) 40 | return 1; 41 | 42 | // OK 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /dub.sdl: -------------------------------------------------------------------------------- 1 | name "mir-lapack" 2 | description "ndslice wrapper for LAPACK" 3 | authors "Ilya Yaroshenko" 4 | copyright "Copyright © 2017-2018, Symmetry Investments & Kaleidic Associates" 5 | license "BSL-1.0" 6 | 7 | dependency "lapack" version=">=0.6.5" 8 | dependency "mir-blas" version=">=1.1.3 <2.0.0" 9 | 10 | configuration "library" { 11 | subConfiguration "mir-blas" "library" 12 | } 13 | 14 | configuration "openblas" { 15 | subConfiguration "mir-blas" "openblas" 16 | } 17 | 18 | configuration "blas" { 19 | subConfiguration "mir-blas" "blas" 20 | libs "lapack" 21 | } 22 | 23 | configuration "cblas" { 24 | subConfiguration "mir-blas" "cblas" 25 | libs "lapack" 26 | } 27 | 28 | configuration "threelib" { 29 | subConfiguration "mir-blas" "twolib" 30 | libs "lapack" 31 | } 32 | 33 | configuration "zerolib" { 34 | subConfiguration "mir-blas" "zerolib" 35 | systemDependencies "mir-lapack configuration zerolib requires user to add specify libraries to link." 36 | } 37 | 38 | configuration "mkl-sequential" { 39 | subConfiguration "mir-blas" "mkl-sequential" 40 | } 41 | 42 | configuration "mkl-sequential-ilp" { 43 | subConfiguration "mir-blas" "mkl-sequential-ilp" 44 | } 45 | 46 | configuration "mkl-tbb-thread" { 47 | subConfiguration "mir-blas" "mkl-tbb-thread" 48 | } 49 | 50 | configuration "mkl-tbb-thread-ilp" { 51 | subConfiguration "mir-blas" "mkl-tbb-thread-ilp" 52 | } 53 | 54 | configuration "mkl-sequential-dll" { 55 | subConfiguration "mir-blas" "mkl-sequential-dll" 56 | } 57 | 58 | configuration "mkl-sequential-ilp-dll" { 59 | subConfiguration "mir-blas" "mkl-sequential-ilp-dll" 60 | } 61 | 62 | configuration "mkl-tbb-thread-dll" { 63 | subConfiguration "mir-blas" "mkl-tbb-thread-dll" 64 | } 65 | 66 | configuration "mkl-tbb-thread-ilp-dll" { 67 | subConfiguration "mir-blas" "mkl-tbb-thread-ilp-dll" 68 | } 69 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('mir-lapack', 'd', 'c', version: '1.2.5', license: 'BSL-1.0') 2 | 3 | description = 'Mir LAPACK - ndslice wrapper for LAPACK' 4 | 5 | cc = meson.get_compiler('c') 6 | lapack_deps = [] 7 | if not cc.find_library('openblas', required : false).found() 8 | lapack_deps = [cc.find_library('lapack')] 9 | endif 10 | 11 | subprojects = ['cblas-d', 'lapack-d', 'mir-core', 'mir-algorithm', 'mir-blas'] 12 | 13 | has_cpp_headers = false 14 | 15 | sources_list = [ 16 | 'mir/lapack', 17 | ] 18 | 19 | sources = [] 20 | foreach s : sources_list 21 | sources += 'source/' + s + '.d' 22 | endforeach 23 | 24 | add_project_arguments([ 25 | '-preview=dip1008', 26 | '-lowmem', 27 | ], language: 'd') 28 | 29 | required_deps = lapack_deps 30 | 31 | foreach p : subprojects 32 | required_deps += dependency(p, fallback : [p, 'this_dep']) 33 | endforeach 34 | 35 | directories = ['source'] 36 | 37 | if has_cpp_headers 38 | directories += 'include' 39 | endif 40 | 41 | directories = include_directories(directories) 42 | 43 | this_lib = library(meson.project_name(), 44 | sources, 45 | include_directories: directories, 46 | install: true, 47 | version: meson.project_version(), 48 | dependencies: required_deps, 49 | ) 50 | 51 | this_dep = declare_dependency( 52 | link_with: [this_lib], 53 | include_directories: directories, 54 | dependencies: required_deps, 55 | ) 56 | 57 | test_versions = [] 58 | 59 | if has_cpp_headers 60 | install_subdir('include/', 61 | strip_directory :true, 62 | install_dir: 'include/', 63 | ) 64 | endif 65 | 66 | install_subdir('source/', 67 | strip_directory : true, 68 | install_dir: 'include/d/' + meson.project_name(), 69 | ) 70 | 71 | import('pkgconfig').generate(this_lib, 72 | description: description, 73 | subdirs: 'd/' + meson.project_name(), 74 | ) 75 | 76 | mir_lapack_dep = this_dep 77 | mir_lapack_lib = this_lib 78 | 79 | test_subdirs = ['examples/gesv'] 80 | -------------------------------------------------------------------------------- /source/mir/lapack.d: -------------------------------------------------------------------------------- 1 | /++ 2 | Low level ndslice wrapper for LAPACK. 3 | 4 | $(RED Attention: LAPACK and this module has column major API.) 5 | ndslice rows correspond to LAPACK columns. 6 | 7 | Functions with `*_wq` suffix are wrappers for workspace queries. 8 | 9 | Authors: Ilya Yaroshenko 10 | Copyright: Copyright © 2017, Symmetry Investments & Kaleidic Associates 11 | +/ 12 | module mir.lapack; 13 | 14 | import mir.ndslice.slice; 15 | import mir.ndslice.topology: retro; 16 | import mir.ndslice.iterator; 17 | import mir.utility: min, max; 18 | import mir.internal.utility : realType, isComplex; 19 | 20 | static import lapack; 21 | 22 | public import lapack: lapackint; 23 | 24 | import lapack.lapack: _cfloat, _cdouble; 25 | 26 | @trusted pure nothrow @nogc: 27 | 28 | /// 29 | lapackint ilaenv()(lapackint ispec, scope const(char)* name, scope const(char)* opts, lapackint n1, lapackint n2, lapackint n3, lapackint n4) 30 | { 31 | return ilaenv_(ispec, name, opts, n1, n2, n3, n4); 32 | } 33 | 34 | /// 35 | lapackint ilaenv2stage()(lapackint ispec, scope const(char)* name, scope const(char)* opts, lapackint n1, lapackint n2, lapackint n3, lapackint n4) 36 | { 37 | return ilaenv2stage_(ispec, name, opts, n1, n2, n3, n4); 38 | } 39 | 40 | /// `getri` work space query. 41 | size_t getri_wq(T)(Slice!(T*, 2, Canonical) a) 42 | in 43 | { 44 | assert(a.length!0 == a.length!1, "getri: The input 'a' must be a square matrix."); 45 | } 46 | do 47 | { 48 | lapackint n = cast(lapackint) a.length; 49 | lapackint lda = cast(lapackint) a._stride.max(1); 50 | T work; 51 | lapackint lwork = -1; 52 | lapackint info; 53 | 54 | lapack.getri_(n, null, lda, null, &work, lwork, info); 55 | 56 | assert(info == 0); 57 | return cast(size_t) work.re; 58 | } 59 | 60 | unittest 61 | { 62 | alias s = getri_wq!float; 63 | alias d = getri_wq!double; 64 | alias c = getri_wq!_cfloat; 65 | alias z = getri_wq!_cdouble; 66 | } 67 | 68 | /// 69 | size_t getri(T)( 70 | Slice!(T*, 2, Canonical) a, 71 | Slice!(lapackint*) ipiv, 72 | Slice!(T*) work, 73 | ) 74 | in 75 | { 76 | assert(a.length!0 == a.length!1, "getri: The input 'a' must be a square matrix."); 77 | assert(ipiv.length == a.length!0, "getri: The length of 'ipiv' must be equal to the number of rows of 'a'."); 78 | assert(work.length, "getri: work must have a non-zero length."); 79 | } 80 | do 81 | { 82 | lapackint n = cast(lapackint) a.length; 83 | lapackint lda = cast(lapackint) a._stride.max(1); 84 | lapackint lwork = cast(lapackint) work.length; 85 | lapackint info; 86 | 87 | lapack.getri_(n, a.iterator, lda, ipiv.iterator, work.iterator, lwork, info); 88 | 89 | assert(info >= 0); 90 | return info; 91 | } 92 | 93 | unittest 94 | { 95 | alias s = getri!float; 96 | alias d = getri!double; 97 | alias c = getri!_cfloat; 98 | alias z = getri!_cdouble; 99 | } 100 | 101 | /// 102 | size_t getrf(T)( 103 | Slice!(T*, 2, Canonical) a, 104 | Slice!(lapackint*) ipiv, 105 | ) 106 | in 107 | { 108 | assert(ipiv.length >= min(a.length!0, a.length!1), "getrf: The length of 'ipiv' must be at least the smaller of 'a''s dimensions"); 109 | } 110 | do 111 | { 112 | lapackint m = cast(lapackint) a.length!1; 113 | lapackint n = cast(lapackint) a.length!0; 114 | lapackint lda = cast(lapackint) a._stride.max(1); 115 | lapackint info; 116 | 117 | lapack.getrf_(m, n, a.iterator, lda, ipiv.iterator, info); 118 | 119 | assert(info >= 0); 120 | return info; 121 | } 122 | 123 | unittest 124 | { 125 | alias s = getrf!float; 126 | alias d = getrf!double; 127 | alias c = getrf!_cfloat; 128 | alias z = getrf!_cdouble; 129 | } 130 | 131 | /// 132 | template sptrf(T) 133 | { 134 | /// `sptrf` for upper triangular input. 135 | size_t sptrf( 136 | Slice!(StairsIterator!(T*, "+")) ap, 137 | Slice!(lapackint*) ipiv, 138 | ) 139 | in 140 | { 141 | assert(ipiv.length == ap.length, "sptrf: The length of 'ipiv' must be equal to the length 'ap'."); 142 | } 143 | do 144 | { 145 | char uplo = 'U'; 146 | lapackint n = cast(lapackint) ap.length; 147 | lapackint info; 148 | 149 | lapack.sptrf_(uplo, n, &ap[0][0], ipiv.iterator, info); 150 | 151 | assert(info >= 0); 152 | return info; 153 | } 154 | 155 | /// `sptrf` for lower triangular input. 156 | size_t sptrf( 157 | Slice!(StairsIterator!(T*, "-")) ap, 158 | Slice!(lapackint*) ipiv, 159 | ) 160 | in 161 | { 162 | assert(ipiv.length == ap.length, "sptrf: The length of 'ipiv' must be equal to the length 'ap'."); 163 | } 164 | do 165 | { 166 | char uplo = 'L'; 167 | lapackint n = cast(lapackint) ap.length; 168 | lapackint info; 169 | 170 | lapack.sptrf_(uplo, n, &ap[0][0], ipiv.iterator, info); 171 | 172 | assert(info >= 0); 173 | return info; 174 | } 175 | } 176 | 177 | unittest 178 | { 179 | alias s = sptrf!float; 180 | alias d = sptrf!double; 181 | } 182 | 183 | /// 184 | size_t gesv(T)( 185 | Slice!(T*, 2, Canonical) a, 186 | Slice!(lapackint*) ipiv, 187 | Slice!(T*, 2, Canonical) b, 188 | ) 189 | in 190 | { 191 | assert(a.length!0 == a.length!1, "gesv: The input 'a' must be a square matrix."); 192 | assert(ipiv.length == a.length!0, "gesv: The length of 'ipiv' must be equal to the number of rows of 'a'."); 193 | assert(b.length!1 == a.length!0, "gesv: The number of columns of 'b' must equal the number of rows of 'a'"); 194 | } 195 | do 196 | { 197 | lapackint n = cast(lapackint) a.length; 198 | lapackint nrhs = cast(lapackint) b.length; 199 | lapackint lda = cast(lapackint) a._stride.max(1); 200 | lapackint ldb = cast(lapackint) b._stride.max(1); 201 | lapackint info; 202 | 203 | lapack.gesv_(n, nrhs, a.iterator, lda, ipiv.iterator, b.iterator, ldb, info); 204 | 205 | assert(info >= 0); 206 | return info; 207 | } 208 | 209 | unittest 210 | { 211 | alias s = gesv!float; 212 | alias d = gesv!double; 213 | } 214 | 215 | /// `gelsd` work space query. 216 | size_t gelsd_wq(T)( 217 | Slice!(T*, 2, Canonical) a, 218 | Slice!(T*, 2, Canonical) b, 219 | ref size_t liwork, 220 | ) 221 | if(!isComplex!T) 222 | in 223 | { 224 | assert(b.length!1 == a.length!1, "gelsd_wq: The number of columns of 'b' must equal the number of columns of 'a'"); 225 | } 226 | do 227 | { 228 | lapackint m = cast(lapackint) a.length!1; 229 | lapackint n = cast(lapackint) a.length!0; 230 | lapackint nrhs = cast(lapackint) b.length; 231 | lapackint lda = cast(lapackint) a._stride.max(1); 232 | lapackint ldb = cast(lapackint) b._stride.max(1); 233 | T rcond; 234 | lapackint rank; 235 | T work; 236 | lapackint lwork = -1; 237 | lapackint iwork; 238 | lapackint info; 239 | 240 | lapack.gelsd_(m, n, nrhs, a.iterator, lda, b.iterator, ldb, null, rcond, rank, &work, lwork, &iwork, info); 241 | 242 | assert(info == 0); 243 | liwork = iwork; 244 | return cast(size_t) work.re; 245 | } 246 | 247 | 248 | /// ditto 249 | size_t gelsd_wq(T)( 250 | Slice!(T*, 2, Canonical) a, 251 | Slice!(T*, 2, Canonical) b, 252 | ref size_t lrwork, 253 | ref size_t liwork, 254 | ) 255 | if(isComplex!T) 256 | in 257 | { 258 | assert(b.length!1 == a.length!1, "gelsd_wq: The number of columns of 'b' must equal the number of columns of 'a'"); 259 | } 260 | do 261 | { 262 | lapackint m = cast(lapackint) a.length!1; 263 | lapackint n = cast(lapackint) a.length!0; 264 | lapackint nrhs = cast(lapackint) b.length; 265 | lapackint lda = cast(lapackint) a._stride.max(1); 266 | lapackint ldb = cast(lapackint) b._stride.max(1); 267 | realType!T rcond; 268 | lapackint rank; 269 | T work; 270 | lapackint lwork = -1; 271 | realType!T rwork; 272 | lapackint iwork; 273 | lapackint info; 274 | 275 | lapack.gelsd_(m, n, nrhs, a.iterator, lda, b.iterator, ldb, null, rcond, rank, &work, lwork, &rwork, &iwork, info); 276 | 277 | assert(info == 0); 278 | lrwork = cast(size_t)rwork; 279 | liwork = iwork; 280 | return cast(size_t) work.re; 281 | } 282 | 283 | unittest 284 | { 285 | alias s = gelsd_wq!float; 286 | alias d = gelsd_wq!double; 287 | alias c = gelsd_wq!_cfloat; 288 | alias z = gelsd_wq!_cdouble; 289 | } 290 | 291 | /// 292 | size_t gelsd(T)( 293 | Slice!(T*, 2, Canonical) a, 294 | Slice!(T*, 2, Canonical) b, 295 | Slice!(T*) s, 296 | T rcond, 297 | ref size_t rank, 298 | Slice!(T*) work, 299 | Slice!(lapackint*) iwork, 300 | ) 301 | if(!isComplex!T) 302 | in 303 | { 304 | assert(b.length!1 == a.length!1, "gelsd: The number of columns of 'b' must equal the number of columns of 'a'"); 305 | assert(s.length == min(a.length!0, a.length!1), "gelsd: The length of 's' must equal the smaller of the dimensions of 'a'"); 306 | } 307 | do 308 | { 309 | lapackint m = cast(lapackint) a.length!1; 310 | lapackint n = cast(lapackint) a.length!0; 311 | lapackint nrhs = cast(lapackint) b.length; 312 | lapackint lda = cast(lapackint) a._stride.max(1); 313 | lapackint ldb = cast(lapackint) b._stride.max(1); 314 | lapackint rank_; 315 | lapackint lwork = cast(lapackint) work.length; 316 | lapackint info; 317 | 318 | lapack.gelsd_(m, n, nrhs, a.iterator, lda, b.iterator, ldb, s.iterator, rcond, rank_, work.iterator, lwork, iwork.iterator, info); 319 | 320 | assert(info >= 0); 321 | rank = rank_; 322 | return info; 323 | } 324 | 325 | /// ditto 326 | size_t gelsd(T)( 327 | Slice!(T*, 2, Canonical) a, 328 | Slice!(T*, 2, Canonical) b, 329 | Slice!(realType!T*) s, 330 | realType!T rcond, 331 | ref size_t rank, 332 | Slice!(T*) work, 333 | Slice!(realType!T*) rwork, 334 | Slice!(lapackint*) iwork, 335 | ) 336 | if(isComplex!T) 337 | in 338 | { 339 | assert(b.length!1 == a.length!1, "gelsd: The number of columns of 'b' must equal the number of columns of 'a'"); 340 | assert(s.length == min(a.length!0, a.length!1), "gelsd: The length of 's' must equal the smaller of the dimensions of 'a'"); 341 | } 342 | do 343 | { 344 | lapackint m = cast(lapackint) a.length!1; 345 | lapackint n = cast(lapackint) a.length!0; 346 | lapackint nrhs = cast(lapackint) b.length; 347 | lapackint lda = cast(lapackint) a._stride.max(1); 348 | lapackint ldb = cast(lapackint) b._stride.max(1); 349 | lapackint rank_; 350 | lapackint lwork = cast(lapackint) work.length; 351 | lapackint info; 352 | 353 | lapack.gelsd_(m, n, nrhs, a.iterator, lda, b.iterator, ldb, s.iterator, rcond, rank_, work.iterator, lwork, rwork.iterator, iwork.iterator, info); 354 | 355 | assert(info >= 0); 356 | rank = rank_; 357 | return info; 358 | } 359 | 360 | unittest 361 | { 362 | alias s = gelsd!float; 363 | alias d = gelsd!double; 364 | alias c = gelsd!_cfloat; 365 | alias z = gelsd!_cdouble; 366 | } 367 | 368 | /// `gesdd` work space query 369 | size_t gesdd_wq(T)( 370 | char jobz, 371 | Slice!(T*, 2, Canonical) a, 372 | Slice!(T*, 2, Canonical) u, 373 | Slice!(T*, 2, Canonical) vt, 374 | ) 375 | { 376 | lapackint m = cast(lapackint) a.length!1; 377 | lapackint n = cast(lapackint) a.length!0; 378 | lapackint lda = cast(lapackint) a._stride.max(1); 379 | lapackint ldu = cast(lapackint) u._stride.max(1); 380 | lapackint ldvt = cast(lapackint) vt._stride.max(1); 381 | T work; 382 | lapackint lwork = -1; 383 | lapackint info; 384 | 385 | static if(!isComplex!T) 386 | { 387 | lapack.gesdd_(jobz, m, n, null, lda, null, null, ldu, null, ldvt, &work, lwork, null, info); 388 | } 389 | else 390 | { 391 | lapack.gesdd_(jobz, m, n, null, lda, null, null, ldu, null, ldvt, &work, lwork, null, null, info); 392 | } 393 | 394 | assert(info == 0); 395 | return cast(size_t) work.re; 396 | } 397 | 398 | unittest 399 | { 400 | alias s = gesdd_wq!float; 401 | alias d = gesdd_wq!double; 402 | alias c = gesdd_wq!_cfloat; 403 | alias z = gesdd_wq!_cdouble; 404 | } 405 | 406 | /// 407 | size_t gesdd(T)( 408 | char jobz, 409 | Slice!(T*, 2, Canonical) a, 410 | Slice!(T*) s, 411 | Slice!(T*, 2, Canonical) u, 412 | Slice!(T*, 2, Canonical) vt, 413 | Slice!(T*) work, 414 | Slice!(lapackint*) iwork, 415 | ) 416 | if(!isComplex!T) 417 | { 418 | lapackint m = cast(lapackint) a.length!1; 419 | lapackint n = cast(lapackint) a.length!0; 420 | lapackint lda = cast(lapackint) a._stride.max(1); 421 | lapackint ldu = cast(lapackint) u._stride.max(1); 422 | lapackint ldvt = cast(lapackint) vt._stride.max(1); 423 | lapackint lwork = cast(lapackint) work.length; 424 | lapackint info; 425 | 426 | lapack.gesdd_(jobz, m, n, a.iterator, lda, s.iterator, u.iterator, ldu, vt.iterator, ldvt, work.iterator, lwork, iwork.iterator, info); 427 | 428 | assert(info >= 0); 429 | return info; 430 | } 431 | 432 | /// ditto 433 | size_t gesdd(T)( 434 | char jobz, 435 | Slice!(T*, 2, Canonical) a, 436 | Slice!(realType!T*) s, 437 | Slice!(T*, 2, Canonical) u, 438 | Slice!(T*, 2, Canonical) vt, 439 | Slice!(T*) work, 440 | Slice!(realType!T*) rwork, 441 | Slice!(lapackint*) iwork, 442 | ) 443 | if(isComplex!T) 444 | { 445 | lapackint m = cast(lapackint) a.length!1; 446 | lapackint n = cast(lapackint) a.length!0; 447 | lapackint lda = cast(lapackint) a._stride.max(1); 448 | lapackint ldu = cast(lapackint) u._stride.max(1); 449 | lapackint ldvt = cast(lapackint) vt._stride.max(1); 450 | lapackint lwork = cast(lapackint) work.length; 451 | lapackint info; 452 | 453 | lapack.gesdd_(jobz, m, n, a.iterator, lda, s.iterator, u.iterator, ldu, vt.iterator, ldvt, work.iterator, lwork, rwork.iterator, iwork.iterator, info); 454 | 455 | assert(info >= 0); 456 | return info; 457 | } 458 | 459 | unittest 460 | { 461 | alias s = gesdd!float; 462 | alias d = gesdd!double; 463 | alias c = gesdd!_cfloat; 464 | alias z = gesdd!_cdouble; 465 | } 466 | 467 | /// `gesvd` work space query 468 | size_t gesvd_wq(T)( 469 | char jobu, 470 | char jobvt, 471 | Slice!(T*, 2, Canonical) a, 472 | Slice!(T*, 2, Canonical) u, 473 | Slice!(T*, 2, Canonical) vt, 474 | ) 475 | { 476 | lapackint m = cast(lapackint) a.length!1; 477 | lapackint n = cast(lapackint) a.length!0; 478 | lapackint lda = cast(lapackint) a._stride.max(1); 479 | lapackint ldu = cast(lapackint) u._stride.max(1); 480 | lapackint ldvt = cast(lapackint) vt._stride.max(1); 481 | T work; 482 | lapackint lwork = -1; 483 | lapackint info; 484 | 485 | static if(!isComplex!T) 486 | { 487 | lapack.gesvd_(jobu, jobvt, m, n, null, lda, null, null, ldu, null, ldvt, &work, lwork, info); 488 | } 489 | else 490 | { 491 | lapack.gesvd_(jobu, jobvt, m, n, null, lda, null, null, ldu, null, ldvt, &work, lwork, null, info); 492 | } 493 | 494 | assert(info == 0); 495 | return cast(size_t) work.re; 496 | } 497 | 498 | unittest 499 | { 500 | alias s = gesvd_wq!float; 501 | alias d = gesvd_wq!double; 502 | alias c = gesvd_wq!_cfloat; 503 | alias z = gesvd_wq!_cdouble; 504 | } 505 | 506 | /// 507 | size_t gesvd(T)( 508 | char jobu, 509 | char jobvt, 510 | Slice!(T*, 2, Canonical) a, 511 | Slice!(T*) s, 512 | Slice!(T*, 2, Canonical) u, 513 | Slice!(T*, 2, Canonical) vt, 514 | Slice!(T*) work, 515 | ) 516 | if(!isComplex!T) 517 | { 518 | lapackint m = cast(lapackint) a.length!1; 519 | lapackint n = cast(lapackint) a.length!0; 520 | lapackint lda = cast(lapackint) a._stride.max(1); 521 | lapackint ldu = cast(lapackint) u._stride.max(1); 522 | lapackint ldvt = cast(lapackint) vt._stride.max(1); 523 | lapackint lwork = cast(lapackint) work.length; 524 | lapackint info; 525 | 526 | lapack.gesvd_(jobu, jobvt, m, n, a.iterator, lda, s.iterator, u.iterator, ldu, vt.iterator, ldvt, work.iterator, lwork, info); 527 | 528 | assert(info >= 0); 529 | return info; 530 | } 531 | 532 | /// ditto 533 | size_t gesvd(T)( 534 | char jobu, 535 | char jobvt, 536 | Slice!(T*, 2, Canonical) a, 537 | Slice!(realType!T*) s, 538 | Slice!(T*, 2, Canonical) u, 539 | Slice!(T*, 2, Canonical) vt, 540 | Slice!(T*) work, 541 | Slice!(realType!T*) rwork, 542 | ) 543 | if(isComplex!T) 544 | { 545 | lapackint m = cast(lapackint) a.length!1; 546 | lapackint n = cast(lapackint) a.length!0; 547 | lapackint lda = cast(lapackint) a._stride.max(1); 548 | lapackint ldu = cast(lapackint) u._stride.max(1); 549 | lapackint ldvt = cast(lapackint) vt._stride.max(1); 550 | lapackint lwork = cast(lapackint) work.length; 551 | lapackint info; 552 | 553 | lapack.gesvd_(jobu, jobvt, m, n, a.iterator, lda, s.iterator, u.iterator, ldu, vt.iterator, ldvt, work.iterator, lwork, rwork.iterator, info); 554 | 555 | assert(info >= 0); 556 | return info; 557 | } 558 | 559 | unittest 560 | { 561 | alias s = gesvd!float; 562 | alias d = gesvd!double; 563 | alias c = gesvd!_cfloat; 564 | alias z = gesvd!_cdouble; 565 | } 566 | 567 | /// 568 | template spev(T) 569 | { 570 | /// 571 | size_t spev( 572 | char jobz, 573 | Slice!(StairsIterator!(T*, "+")) ap, 574 | Slice!(T*) w, 575 | Slice!(T*, 2, Canonical) z, 576 | Slice!(T*) work, 577 | ) 578 | in 579 | { 580 | assert(work.length == 3 * ap.length, "spev: The length of 'work' must equal three times the length of 'ap'."); 581 | assert(w.length == ap.length, "spev: The length of 'w' must equal the length of 'ap'."); 582 | } 583 | do 584 | { 585 | char uplo = 'U'; 586 | lapackint n = cast(lapackint) ap.length; 587 | lapackint ldz = cast(lapackint) z._stride.max(1); 588 | lapackint info; 589 | 590 | lapack.spev_(jobz, uplo, n, &ap[0][0], w.iterator, z.iterator, ldz, work.iterator, info); 591 | 592 | assert(info >= 0); 593 | return info; 594 | } 595 | 596 | /// 597 | size_t spev( 598 | char jobz, 599 | Slice!(StairsIterator!(T*, "-")) ap, 600 | Slice!(T*) w, 601 | Slice!(T*, 2, Canonical) z, 602 | Slice!(T*) work, 603 | ) 604 | in 605 | { 606 | assert(work.length == 3 * ap.length, "spev: The length of 'work' must equal three times the length of 'ap'."); 607 | assert(w.length == ap.length, "spev: The length of 'w' must equal the length of 'ap'."); 608 | } 609 | do 610 | { 611 | char uplo = 'L'; 612 | lapackint n = cast(lapackint) ap.length; 613 | lapackint ldz = cast(lapackint) z._stride.max(1); 614 | lapackint info; 615 | 616 | lapack.spev_(jobz, uplo, n, &ap[0][0], w.iterator, z.iterator, ldz, work.iterator, info); 617 | 618 | assert(info >= 0); 619 | return info; 620 | } 621 | } 622 | 623 | unittest 624 | { 625 | alias s = spev!float; 626 | alias d = spev!double; 627 | } 628 | 629 | /// 630 | size_t sytrf(T)( 631 | char uplo, 632 | Slice!(T*, 2, Canonical) a, 633 | Slice!(lapackint*) ipiv, 634 | Slice!(T*) work, 635 | ) 636 | in 637 | { 638 | assert(a.length!0 == a.length!1, "sytrf: The input 'a' must be a square matrix."); 639 | } 640 | do 641 | { 642 | lapackint info; 643 | lapackint n = cast(lapackint) a.length; 644 | lapackint lda = cast(lapackint) a._stride.max(1); 645 | lapackint lwork = cast(lapackint) work.length; 646 | 647 | lapack.sytrf_(uplo, n, a.iterator, lda, ipiv.iterator, work.iterator, lwork, info); 648 | ///if info = 0: successful exit. 649 | ///if info > 0: if info = i, D(i, i) is exactly zero. The factorization has been 650 | ///completed, but the block diagonal matrix D is exactly singular, and division by 651 | ///zero will occur if it is used to solve a system of equations. 652 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 653 | assert(info >= 0); 654 | return info; 655 | } 656 | 657 | unittest 658 | { 659 | alias s = sytrf!float; 660 | alias d = sytrf!double; 661 | alias c = sytrf!_cfloat; 662 | alias z = sytrf!_cdouble; 663 | } 664 | 665 | /// 666 | size_t geqrf(T)( 667 | Slice!(T*, 2, Canonical) a, 668 | Slice!(T*) tau, 669 | Slice!(T*) work 670 | ) 671 | in 672 | { 673 | assert(a.length!0 >= 0, "geqrf: The number of columns of 'a' must be " ~ 674 | "greater than or equal to zero."); //n>=0 675 | assert(a.length!1 >= a.length!0, "geqrf: The number of columns of 'a' " ~ 676 | "must be greater than or equal to the number of its rows."); //m>=n 677 | assert(tau.length >= 0, "geqrf: The input 'tau' must have length greater " ~ 678 | "than or equal to zero."); //k>=0 679 | assert(a.length!0 >= tau.length, "geqrf: The number of columns of 'a' " ~ 680 | "must be greater than or equal to the length of 'tau'."); //n>=k 681 | assert(work.length >= a.length!0, "geqrf: The length of 'work' must be " ~ 682 | "greater than or equal to the number of rows of 'a'."); //lwork>=n 683 | } 684 | do 685 | { 686 | lapackint m = cast(lapackint) a.length!1; 687 | lapackint n = cast(lapackint) a.length!0; 688 | lapackint lda = cast(lapackint) a._stride.max(1); 689 | lapackint lwork = cast(lapackint) work.length; 690 | lapackint info; 691 | 692 | lapack.geqrf_(m, n, a.iterator, lda, tau.iterator, work.iterator, lwork, info); 693 | 694 | ///if info == 0: successful exit; 695 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 696 | assert(info >= 0); 697 | return info; 698 | } 699 | 700 | unittest 701 | { 702 | alias s = geqrf!float; 703 | alias d = geqrf!double; 704 | alias c = geqrf!_cfloat; 705 | alias z = geqrf!_cdouble; 706 | } 707 | 708 | /// 709 | size_t getrs(T)( 710 | char trans, 711 | Slice!(T*, 2, Canonical) a, 712 | Slice!(T*, 2, Canonical) b, 713 | Slice!(lapackint*) ipiv, 714 | ) 715 | in 716 | { 717 | assert(a.length!0 == a.length!1, "getrs: The input 'a' must be a square matrix."); 718 | assert(ipiv.length == a.length!0, "getrs: The length of 'ipiv' must be equal to the number of rows of 'a'."); 719 | } 720 | do 721 | { 722 | lapackint n = cast(lapackint) a.length; 723 | lapackint nrhs = cast(lapackint) b.length; 724 | lapackint lda = cast(lapackint) a._stride.max(1); 725 | lapackint ldb = cast(lapackint) b._stride.max(1); 726 | lapackint info; 727 | 728 | lapack.getrs_(trans, n, nrhs, a.iterator, lda, ipiv.iterator, b.iterator, ldb, info); 729 | 730 | ///if info == 0: successful exit. 731 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 732 | assert(info >= 0); 733 | return info; 734 | } 735 | 736 | unittest 737 | { 738 | alias s = getrs!float; 739 | alias d = getrs!double; 740 | alias c = getrs!_cfloat; 741 | alias z = getrs!_cdouble; 742 | } 743 | 744 | /// 745 | size_t potrs(T)( 746 | char uplo, 747 | Slice!(T*, 2, Canonical) a, 748 | Slice!(T*, 2, Canonical) b, 749 | ) 750 | in 751 | { 752 | assert(a.length!0 == a.length!1, "potrs: The input 'a' must be a square matrix."); 753 | } 754 | do 755 | { 756 | lapackint n = cast(lapackint) a.length; 757 | lapackint nrhs = cast(lapackint) b.length; 758 | lapackint lda = cast(lapackint) a._stride.max(1); 759 | lapackint ldb = cast(lapackint) b._stride.max(1); 760 | lapackint info; 761 | 762 | lapack.potrs_(uplo, n, nrhs, a.iterator, lda, b.iterator, ldb, info); 763 | 764 | ///if info == 0: successful exit. 765 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 766 | assert(info >= 0); 767 | return info; 768 | } 769 | 770 | unittest 771 | { 772 | alias s = potrs!float; 773 | alias d = potrs!double; 774 | alias c = potrs!_cfloat; 775 | alias z = potrs!_cdouble; 776 | } 777 | 778 | /// 779 | size_t sytrs2(T)( 780 | Slice!(T*, 2, Canonical) a, 781 | Slice!(T*, 2, Canonical) b, 782 | Slice!(lapackint*) ipiv, 783 | Slice!(T*) work, 784 | char uplo, 785 | ) 786 | in 787 | { 788 | assert(a.length!0 == a.length!1, "sytrs2: The input 'a' must be a square matrix."); 789 | } 790 | do 791 | { 792 | lapackint n = cast(lapackint) a.length; 793 | lapackint nrhs = cast(lapackint) b.length; 794 | lapackint lda = cast(lapackint) a._stride.max(1); 795 | lapackint ldb = cast(lapackint) b._stride.max(1); 796 | lapackint info; 797 | 798 | lapack.sytrs2_(uplo, n, nrhs, a.iterator, lda, ipiv.iterator, b.iterator, ldb, work.iterator, info); 799 | 800 | ///if info == 0: successful exit. 801 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 802 | assert(info >= 0); 803 | return info; 804 | } 805 | 806 | unittest 807 | { 808 | alias s = sytrs2!float; 809 | alias d = sytrs2!double; 810 | alias c = sytrs2!_cfloat; 811 | alias z = sytrs2!_cdouble; 812 | } 813 | 814 | /// 815 | size_t geqrs(T)( 816 | Slice!(T*, 2, Canonical) a, 817 | Slice!(T*, 2, Canonical) b, 818 | Slice!(T*) tau, 819 | Slice!(T*) work 820 | ) 821 | in 822 | { 823 | assert(a.length!0 >= 0, "geqrs: The number of columns of 'a' must be " ~ 824 | "greater than or equal to zero."); //n>=0 825 | assert(a.length!1 >= a.length!0, "geqrs: The number of columns of 'a' " ~ 826 | "must be greater than or equal to the number of its rows."); //m>=n 827 | assert(tau.length >= 0, "geqrs: The input 'tau' must have length greater " ~ 828 | "than or equal to zero."); //k>=0 829 | assert(a.length!0 >= tau.length, "geqrs: The number of columns of 'a' " ~ 830 | "must be greater than or equal to the length of 'tau'."); //n>=k 831 | assert(work.length >= a.length!0, "geqrs: The length of 'work' must be " ~ 832 | "greater than or equal to the number of rows of 'a'."); //lwork>=n 833 | } 834 | do 835 | { 836 | lapackint m = cast(lapackint) a.length!1; 837 | lapackint n = cast(lapackint) a.length!0; 838 | lapackint nrhs = cast(lapackint) b.length; 839 | lapackint lda = cast(lapackint) a._stride.max(1); 840 | lapackint ldb = cast(lapackint) b._stride.max(1); 841 | lapackint lwork = cast(lapackint) work.length; 842 | lapackint info; 843 | 844 | lapack.geqrs_(m, n, nrhs, a.iterator, lda, tau.iterator, b.iterator, ldb, work.iterator, lwork, info); 845 | 846 | ///if info == 0: successful exit. 847 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 848 | assert(info >= 0); 849 | return info; 850 | } 851 | 852 | version(none) 853 | unittest 854 | { 855 | alias s = geqrs!float; 856 | alias d = geqrs!double; 857 | alias c = geqrs!_cfloat; 858 | alias z = geqrs!_cdouble; 859 | } 860 | 861 | /// 862 | size_t sysv_rook_wk(T)( 863 | char uplo, 864 | Slice!(T*, 2, Canonical) a, 865 | Slice!(T*, 2, Canonical) b, 866 | ) 867 | in 868 | { 869 | assert(a.length!0 == a.length!1, "sysv_rook_wk: The input 'a' must be a square matrix."); 870 | assert(b.length!1 == a.length!0, "sysv_rook_wk: The number of columns of 'b' must equal the number of rows of 'a'."); 871 | } 872 | do 873 | { 874 | lapackint n = cast(lapackint) a.length; 875 | lapackint nrhs = cast(lapackint) b.length; 876 | lapackint lda = cast(lapackint) a._stride.max(1); 877 | lapackint ldb = cast(lapackint) b._stride.max(1); 878 | T work; 879 | lapackint lwork = -1; 880 | lapackint info; 881 | 882 | lapack.sysv_rook_(uplo, n, nrhs, a._iterator, lda, null, b._iterator, ldb, &work, lwork, info); 883 | 884 | return cast(size_t) work.re; 885 | } 886 | 887 | unittest 888 | { 889 | alias s = sysv_rook_wk!float; 890 | alias d = sysv_rook_wk!double; 891 | alias c = sysv_rook_wk!_cfloat; 892 | alias z = sysv_rook_wk!_cdouble; 893 | } 894 | 895 | /// 896 | size_t sysv_rook(T)( 897 | char uplo, 898 | Slice!(T*, 2, Canonical) a, 899 | Slice!(lapackint*) ipiv, 900 | Slice!(T*, 2, Canonical) b, 901 | Slice!(T*) work, 902 | ) 903 | in 904 | { 905 | assert(a.length!0 == a.length!1, "sysv_rook: The input 'a' must be a square matrix."); 906 | assert(ipiv.length == a.length!0, "sysv_rook: The length of 'ipiv' must be equal to the number of rows of 'a'"); 907 | assert(b.length!1 == a.length!0, "sysv_rook: The number of columns of 'b' must equal the number of rows of 'a'."); 908 | } 909 | do 910 | { 911 | lapackint n = cast(lapackint) a.length; 912 | lapackint nrhs = cast(lapackint) b.length; 913 | lapackint lda = cast(lapackint) a._stride.max(1); 914 | lapackint ldb = cast(lapackint) b._stride.max(1); 915 | lapackint lwork = cast(lapackint) work.length; 916 | lapackint info; 917 | 918 | lapack.sysv_rook_(uplo, n, nrhs, a._iterator, lda, ipiv._iterator, b._iterator, ldb, work._iterator, lwork, info); 919 | 920 | assert(info >= 0); 921 | return info; 922 | } 923 | 924 | unittest 925 | { 926 | alias s = sysv_rook!float; 927 | alias d = sysv_rook!double; 928 | alias c = sysv_rook!_cfloat; 929 | alias z = sysv_rook!_cdouble; 930 | } 931 | 932 | /// 933 | size_t syev_wk(T)( 934 | char jobz, 935 | char uplo, 936 | Slice!(T*, 2, Canonical) a, 937 | Slice!(T*) w, 938 | ) 939 | in 940 | { 941 | assert(a.length!0 == a.length!1, "syev_wk: The input 'a' must be a square matrix."); 942 | assert(w.length == a.length!0, "syev_wk: The length of 'w' must equal the number of rows of 'a'."); 943 | } 944 | do 945 | { 946 | lapackint n = cast(lapackint) a.length; 947 | lapackint lda = cast(lapackint) a._stride.max(1); 948 | T work; 949 | lapackint lwork = -1; 950 | lapackint info; 951 | 952 | lapack.syev_(jobz, uplo, n, a._iterator, lda, w._iterator, &work, lwork, info); 953 | 954 | return cast(size_t) work.re; 955 | } 956 | 957 | unittest 958 | { 959 | alias s = syev_wk!float; 960 | alias d = syev_wk!double; 961 | } 962 | 963 | /// 964 | size_t syev(T)( 965 | char jobz, 966 | char uplo, 967 | Slice!(T*, 2, Canonical) a, 968 | Slice!(T*) w, 969 | Slice!(T*) work, 970 | ) 971 | in 972 | { 973 | assert(a.length!0 == a.length!1, "syev: The input 'a' must be a square matrix."); 974 | assert(w.length == a.length!0, "syev: The length of 'w' must equal the number of rows of 'a'."); 975 | } 976 | do 977 | { 978 | lapackint n = cast(lapackint) a.length; 979 | lapackint lda = cast(lapackint) a._stride.max(1); 980 | lapackint lwork = cast(lapackint) work.length; 981 | lapackint info; 982 | 983 | lapack.syev_(jobz, uplo, n, a._iterator, lda, w._iterator, work._iterator, lwork, info); 984 | 985 | assert(info >= 0); 986 | return info; 987 | } 988 | 989 | unittest 990 | { 991 | alias s = syev!float; 992 | alias d = syev!double; 993 | } 994 | 995 | /// 996 | size_t syev_2stage_wk(T)( 997 | char jobz, 998 | char uplo, 999 | Slice!(T*, 2, Canonical) a, 1000 | Slice!(T*) w, 1001 | ) 1002 | in 1003 | { 1004 | assert(a.length!0 == a.length!1, "syev_2stage_wk: The input 'a' must be a square matrix."); 1005 | assert(w.length == a.length, "syev_2stage_wk: The length of 'w' must equal the number of rows of 'a'."); 1006 | } 1007 | do 1008 | { 1009 | lapackint n = cast(lapackint) a.length; 1010 | lapackint lda = cast(lapackint) a._stride.max(1); 1011 | T work; 1012 | lapackint lwork = -1; 1013 | lapackint info; 1014 | 1015 | lapack.syev_2stage_(jobz, uplo, n, a._iterator, lda, w._iterator, &work, lwork, info); 1016 | 1017 | return cast(size_t) work.re; 1018 | } 1019 | 1020 | version(none) 1021 | unittest 1022 | { 1023 | alias s = syev_2stage_wk!float; 1024 | alias d = syev_2stage_wk!double; 1025 | } 1026 | 1027 | /// 1028 | size_t syev_2stage(T)( 1029 | char jobz, 1030 | char uplo, 1031 | Slice!(T*, 2, Canonical) a, 1032 | Slice!(T*) w, 1033 | Slice!(T*) work, 1034 | ) 1035 | in 1036 | { 1037 | assert(a.length!0 == a.length!1, "syev_2stage: The input 'a' must be a square matrix."); 1038 | assert(w.length == a.length, "syev_2stage: The length of 'w' must equal the number of rows of 'a'."); 1039 | } 1040 | do 1041 | { 1042 | lapackint n = cast(lapackint) a.length; 1043 | lapackint lda = cast(lapackint) a._stride.max(1); 1044 | lapackint lwork = cast(lapackint) work.length; 1045 | lapackint info; 1046 | 1047 | lapack.syev_2stage_(jobz, uplo, n, a._iterator, lda, w._iterator, work._iterator, lwork, info); 1048 | 1049 | assert(info >= 0); 1050 | return info; 1051 | } 1052 | 1053 | version(none) 1054 | unittest 1055 | { 1056 | alias s = syev_2stage!float; 1057 | alias d = syev_2stage!double; 1058 | } 1059 | 1060 | /// 1061 | size_t potrf(T)( 1062 | char uplo, 1063 | Slice!(T*, 2, Canonical) a, 1064 | ) 1065 | in 1066 | { 1067 | assert(a.length!0 == a.length!1, "potrf: The input 'a' must be a square matrix."); 1068 | } 1069 | do 1070 | { 1071 | lapackint n = cast(lapackint) a.length; 1072 | lapackint lda = cast(lapackint) a._stride.max(1); 1073 | lapackint info; 1074 | 1075 | lapack.potrf_(uplo, n, a.iterator, lda, info); 1076 | 1077 | assert(info >= 0); 1078 | 1079 | return info; 1080 | } 1081 | 1082 | unittest 1083 | { 1084 | alias s = potrf!float; 1085 | alias d = potrf!double; 1086 | alias c = potrf!_cfloat; 1087 | alias z = potrf!_cdouble; 1088 | } 1089 | 1090 | /// 1091 | size_t pptrf(T)( 1092 | char uplo, 1093 | Slice!(T*, 2, Canonical) ap, 1094 | ) 1095 | { 1096 | lapackint n = cast(lapackint) ap.length; 1097 | lapackint info; 1098 | 1099 | lapack.pptrf_(uplo, n, ap.iterator, info); 1100 | 1101 | assert(info >= 0); 1102 | 1103 | return info; 1104 | } 1105 | 1106 | unittest 1107 | { 1108 | alias s = pptrf!float; 1109 | alias d = pptrf!double; 1110 | alias c = pptrf!_cfloat; 1111 | alias z = pptrf!_cdouble; 1112 | } 1113 | 1114 | /// 1115 | template sptri(T) 1116 | { 1117 | /// `sptri` for upper triangular input. 1118 | size_t sptri( 1119 | Slice!(StairsIterator!(T*, "+")) ap, 1120 | Slice!(lapackint*) ipiv, 1121 | Slice!(T*) work 1122 | ) 1123 | in 1124 | { 1125 | assert(ipiv.length == ap.length, "sptri: The length of 'ipiv' must be equal to the length of 'ap'."); 1126 | assert(work.length == ap.length, "sptri: The length of 'work' must be equal to the length of 'ap'."); 1127 | } 1128 | do 1129 | { 1130 | lapackint n = cast(lapackint) ap.length; 1131 | lapackint info; 1132 | 1133 | char uplo = 'U'; 1134 | lapack.sptri_(uplo, n, &ap[0][0], ipiv.iterator, work.iterator, info); 1135 | 1136 | assert(info >= 0); 1137 | return info; 1138 | } 1139 | 1140 | /// `sptri` for lower triangular input. 1141 | size_t sptri( 1142 | Slice!(StairsIterator!(T*, "-")) ap, 1143 | Slice!(lapackint*) ipiv, 1144 | Slice!(T*) work 1145 | ) 1146 | in 1147 | { 1148 | assert(ipiv.length == ap.length, "sptri: The length of 'ipiv' must be equal to the length of 'ap'."); 1149 | assert(work.length == ap.length, "sptri: The length of 'work' must be equal to the length of 'ap'."); 1150 | } 1151 | do 1152 | { 1153 | lapackint n = cast(lapackint) ap.length; 1154 | lapackint info; 1155 | 1156 | char uplo = 'L'; 1157 | lapack.sptri_(uplo, n, &ap[0][0], ipiv.iterator, work.iterator, info); 1158 | 1159 | assert(info >= 0); 1160 | return info; 1161 | } 1162 | } 1163 | 1164 | unittest 1165 | { 1166 | alias s = sptri!float; 1167 | alias d = sptri!double; 1168 | alias c = sptri!_cfloat; 1169 | alias z = sptri!_cdouble; 1170 | } 1171 | 1172 | /// 1173 | size_t potri(T)( 1174 | char uplo, 1175 | Slice!(T*, 2, Canonical) a, 1176 | ) 1177 | in 1178 | { 1179 | assert(a.length!0 == a.length!1, "potri: The input 'a' must be a square matrix."); 1180 | } 1181 | do 1182 | { 1183 | lapackint n = cast(lapackint) a.length; 1184 | lapackint lda = cast(lapackint) a._stride.max(1); 1185 | lapackint info; 1186 | 1187 | lapack.potri_(uplo, n, a.iterator, lda, info); 1188 | 1189 | assert(info >= 0); 1190 | return info; 1191 | } 1192 | 1193 | unittest 1194 | { 1195 | alias s = potri!float; 1196 | alias d = potri!double; 1197 | alias c = potri!_cfloat; 1198 | alias z = potri!_cdouble; 1199 | } 1200 | 1201 | /// 1202 | template pptri(T) 1203 | { 1204 | /// `pptri` for upper triangular input. 1205 | size_t pptri( 1206 | Slice!(StairsIterator!(T*, "+")) ap 1207 | ) 1208 | { 1209 | lapackint n = cast(lapackint) ap.length; 1210 | lapackint info; 1211 | 1212 | char uplo = 'U'; 1213 | lapack.pptri_(uplo, n, &ap[0][0], info); 1214 | 1215 | assert(info >= 0); 1216 | return info; 1217 | } 1218 | 1219 | /// `pptri` for lower triangular input. 1220 | size_t pptri( 1221 | Slice!(StairsIterator!(T*, "-")) ap 1222 | ) 1223 | { 1224 | lapackint n = cast(lapackint) ap.length; 1225 | lapackint info; 1226 | 1227 | char uplo = 'L'; 1228 | lapack.pptri_(uplo, n, &ap[0][0], info); 1229 | 1230 | assert(info >= 0); 1231 | return info; 1232 | } 1233 | } 1234 | 1235 | unittest 1236 | { 1237 | alias s = pptri!float; 1238 | alias d = pptri!double; 1239 | alias c = pptri!_cfloat; 1240 | alias z = pptri!_cdouble; 1241 | } 1242 | 1243 | /// 1244 | size_t trtri(T)( 1245 | char uplo, 1246 | char diag, 1247 | Slice!(T*, 2, Canonical) a, 1248 | ) 1249 | in 1250 | { 1251 | assert(a.length!0 == a.length!1, "trtri: The input 'a' must be a square matrix."); 1252 | } 1253 | do 1254 | { 1255 | lapackint n = cast(lapackint) a.length; 1256 | lapackint lda = cast(lapackint) a._stride.max(1); 1257 | lapackint info; 1258 | 1259 | lapack.trtri_(uplo, diag, n, a.iterator, lda, info); 1260 | 1261 | assert(info >= 0); 1262 | return info; 1263 | } 1264 | 1265 | unittest 1266 | { 1267 | alias s = trtri!float; 1268 | alias d = trtri!double; 1269 | alias c = trtri!_cfloat; 1270 | alias z = trtri!_cdouble; 1271 | } 1272 | 1273 | /// 1274 | size_t gtsv(T)( 1275 | Slice!(T*) dl, 1276 | Slice!(T*) d, 1277 | Slice!(T*) du, 1278 | Slice!(T*, 2, Canonical) b, 1279 | ) 1280 | in (d.length == 0 && dl.length == 0 || dl.length + 1 == d.length, "gtsv: 'dl' has to have length equal to N - 1, where N is length of 'd'.") 1281 | in (du.length == dl.length, "gtsv: 'du' has to have length equal to N - 1, where N is length of 'd'.") 1282 | in (d.length!0 == b.length!1, "gtsv: The input 'b' has to be N-by-NRHS matrix where N is length of 'd'.") 1283 | out (info; info >= 0) 1284 | { 1285 | 1286 | lapackint n = cast(lapackint) b.length!1; 1287 | lapackint nrhs = cast(lapackint) b.length; 1288 | lapackint ldb = cast(lapackint) b._stride.max(1); 1289 | lapackint info; 1290 | 1291 | lapack.gtsv_(n, nrhs, dl.iterator, d.iterator, du.iterator, b.iterator, ldb, info); 1292 | return info; 1293 | } 1294 | 1295 | unittest 1296 | { 1297 | alias s = gtsv!float; 1298 | alias d = gtsv!double; 1299 | alias c = gtsv!_cfloat; 1300 | alias z = gtsv!_cdouble; 1301 | } 1302 | 1303 | /// 1304 | size_t trtrs(T)( 1305 | char uplo, 1306 | char diag, 1307 | char trans, 1308 | Slice!(const(T)*, 2, Canonical) a, 1309 | Slice!(T*, 2, Canonical) b, 1310 | ) 1311 | in (a.length!0 == a.length!1, "trtrs: The input 'a' must be a square matrix.") 1312 | in (a.length!0 == b.length!1, "trtrs: The input 'b' has to be N-by-NRHS matrix where N is order of 'a'.") 1313 | out (info; info >= 0) 1314 | { 1315 | lapackint n = cast(lapackint) a.length; 1316 | lapackint nrhs = cast(lapackint) b.length; 1317 | lapackint lda = cast(lapackint) a._stride.max(1); 1318 | lapackint ldb = cast(lapackint) b._stride.max(1); 1319 | lapackint info; 1320 | 1321 | lapack.trtrs_(uplo, diag, trans, n, nrhs, a.iterator, lda, b.iterator, ldb, info); 1322 | return info; 1323 | } 1324 | 1325 | unittest 1326 | { 1327 | alias s = trtrs!float; 1328 | alias d = trtrs!double; 1329 | alias c = trtrs!_cfloat; 1330 | alias z = trtrs!_cdouble; 1331 | } 1332 | 1333 | /// 1334 | template tptri(T) 1335 | { 1336 | /// `tptri` for upper triangular input. 1337 | size_t tptri( 1338 | char diag, 1339 | Slice!(StairsIterator!(T*, "+")) ap, 1340 | ) 1341 | { 1342 | lapackint n = cast(lapackint) ap.length; 1343 | lapackint info; 1344 | 1345 | char uplo = 'U'; 1346 | lapack.tptri_(uplo, diag, n, &ap[0][0], info); 1347 | 1348 | assert(info >= 0); 1349 | return info; 1350 | } 1351 | 1352 | /// `tptri` for lower triangular input. 1353 | size_t tptri( 1354 | char diag, 1355 | Slice!(StairsIterator!(T*, "-")) ap, 1356 | ) 1357 | { 1358 | lapackint n = cast(lapackint) ap.length; 1359 | lapackint info; 1360 | 1361 | char uplo = 'L'; 1362 | lapack.tptri_(uplo, diag, n, &ap[0][0], info); 1363 | 1364 | assert(info >= 0); 1365 | return info; 1366 | 1367 | } 1368 | } 1369 | 1370 | unittest 1371 | { 1372 | alias s = tptri!float; 1373 | alias d = tptri!double; 1374 | alias c = tptri!_cfloat; 1375 | alias z = tptri!_cdouble; 1376 | } 1377 | 1378 | /// 1379 | size_t ormqr(T)( 1380 | char side, 1381 | char trans, 1382 | Slice!(T*, 2, Canonical) a, 1383 | Slice!(T*) tau, 1384 | Slice!(T*, 2, Canonical) c, 1385 | Slice!(T*) work, 1386 | ) 1387 | { 1388 | lapackint m = cast(lapackint) c.length!1; 1389 | lapackint n = cast(lapackint) c.length!0; 1390 | lapackint k = cast(lapackint) tau.length; 1391 | lapackint lda = cast(lapackint) a._stride.max(1); 1392 | lapackint ldc = cast(lapackint) c._stride.max(1); 1393 | lapackint lwork = cast(lapackint) work.length; 1394 | lapackint info; 1395 | 1396 | lapack.ormqr_(side, trans, m, n, k, a.iterator, lda, tau.iterator, c.iterator, ldc, work.iterator, lwork, info); 1397 | 1398 | ///if info == 0: successful exit. 1399 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 1400 | assert(info >= 0); 1401 | return info; 1402 | } 1403 | 1404 | unittest 1405 | { 1406 | alias s = ormqr!float; 1407 | alias d = ormqr!double; 1408 | } 1409 | 1410 | /// 1411 | size_t unmqr(T)( 1412 | char side, 1413 | char trans, 1414 | Slice!(T*, 2, Canonical) a, 1415 | Slice!(T*) tau, 1416 | Slice!(T*, 2, Canonical) c, 1417 | Slice!(T*) work, 1418 | ) 1419 | { 1420 | lapackint m = cast(lapackint) c.length!1; 1421 | lapackint n = cast(lapackint) c.length!0; 1422 | lapackint k = cast(lapackint) tau.length; 1423 | lapackint lda = cast(lapackint) a._stride.max(1); 1424 | lapackint ldc = cast(lapackint) c._stride.max(1); 1425 | lapackint lwork = cast(lapackint) work.length; 1426 | lapackint info; 1427 | 1428 | lapack.unmqr_(side, trans, m, n, k, a.iterator, lda, tau.iterator, c.iterator, ldc, work.iterator, lwork, info); 1429 | 1430 | ///if info == 0: successful exit. 1431 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 1432 | assert(info >= 0); 1433 | return info; 1434 | } 1435 | 1436 | unittest 1437 | { 1438 | alias s = unmqr!_cfloat; 1439 | alias d = unmqr!_cdouble; 1440 | } 1441 | 1442 | /// 1443 | size_t orgqr(T)( 1444 | Slice!(T*, 2, Canonical) a, 1445 | Slice!(T*) tau, 1446 | Slice!(T*) work, 1447 | ) 1448 | in 1449 | { 1450 | assert(a.length!0 >= 0, "orgqr: The number of columns of 'a' must be " ~ 1451 | "greater than or equal to zero."); //n>=0 1452 | assert(a.length!1 >= a.length!0, "orgqr: The number of columns of 'a' " ~ 1453 | "must be greater than or equal to the number of its rows."); //m>=n 1454 | assert(tau.length >= 0, "orgqr: The input 'tau' must have length greater " ~ 1455 | "than or equal to zero."); //k>=0 1456 | assert(a.length!0 >= tau.length, "orgqr: The number of columns of 'a' " ~ 1457 | "must be greater than or equal to the length of 'tau'."); //n>=k 1458 | assert(work.length >= a.length!0, "orgqr: The length of 'work' must be " ~ 1459 | "greater than or equal to the number of rows of 'a'."); //lwork>=n 1460 | } 1461 | do 1462 | { 1463 | lapackint m = cast(lapackint) a.length!1; 1464 | lapackint n = cast(lapackint) a.length!0; 1465 | lapackint k = cast(lapackint) tau.length; 1466 | lapackint lda = cast(lapackint) a._stride.max(1); 1467 | lapackint lwork = cast(lapackint) work.length; 1468 | lapackint info; 1469 | 1470 | lapack.orgqr_(m, n, k, a.iterator, lda, tau.iterator, work.iterator, lwork, info); 1471 | 1472 | ///if info == 0: successful exit. 1473 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 1474 | assert(info >= 0); 1475 | return info; 1476 | } 1477 | 1478 | unittest 1479 | { 1480 | alias s = orgqr!float; 1481 | alias d = orgqr!double; 1482 | } 1483 | 1484 | /// 1485 | size_t ungqr(T)( 1486 | Slice!(T*, 2, Canonical) a, 1487 | Slice!(T*) tau, 1488 | Slice!(T*) work, 1489 | ) 1490 | in 1491 | { 1492 | assert(a.length!1 >= a.length!0, "ungqr: The number of columns of 'a' must be greater than or equal to the number of its rows."); //m>=n 1493 | assert(a.length!0 >= tau.length, "ungqr: The number of columns of 'a' must be greater than or equal to the length of 'tau'."); //n>=k 1494 | assert(work.length >= a.length!0, "ungqr: The length of 'work' must be greater than or equal to the number of rows of 'a'."); //lwork>=n 1495 | } 1496 | do 1497 | { 1498 | lapackint m = cast(lapackint) a.length!1; 1499 | lapackint n = cast(lapackint) a.length!0; 1500 | lapackint k = cast(lapackint) tau.length; 1501 | lapackint lda = cast(lapackint) a._stride.max(1); 1502 | lapackint lwork = cast(lapackint) work.length; 1503 | lapackint info; 1504 | 1505 | lapack.ungqr_(m, n, k, a.iterator, lda, tau.iterator, work.iterator, lwork, info); 1506 | 1507 | ///if info == 0: successful exit. 1508 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 1509 | assert(info >= 0); 1510 | return info; 1511 | } 1512 | 1513 | unittest 1514 | { 1515 | alias s = ungqr!_cfloat; 1516 | alias d = ungqr!_cdouble; 1517 | } 1518 | 1519 | alias orghr = unghr; // this is the name for the real type vairant of ungqr 1520 | 1521 | /// 1522 | size_t unghr(T)( 1523 | Slice!(T*, 2, Canonical) a, 1524 | Slice!(T*) tau, 1525 | Slice!(T*) work, 1526 | ) 1527 | in 1528 | { 1529 | assert(a.length!1 >= a.length!0); //m>=n 1530 | assert(a.length!0 >= tau.length); //n>=k 1531 | assert(work.length >= a.length!0); //lwork>=n 1532 | } 1533 | do 1534 | { 1535 | lapackint m = cast(lapackint) a.length!1; 1536 | lapackint n = cast(lapackint) a.length!0; 1537 | lapackint k = cast(lapackint) tau.length; 1538 | lapackint lda = cast(lapackint) a._stride.max(1); 1539 | lapackint lwork = cast(lapackint) work.length; 1540 | lapackint info; 1541 | static if (isComplex!T){ 1542 | lapack.ungqr_(m, n, k, a.iterator, lda, tau.iterator, work.iterator, lwork, info); 1543 | } 1544 | else { 1545 | lapack.orgqr_(m, n, k, a.iterator, lda, tau.iterator, work.iterator, lwork, info); 1546 | } 1547 | 1548 | ///if info == 0: successful exit. 1549 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 1550 | assert(info >= 0); 1551 | return cast(size_t)info; 1552 | } 1553 | 1554 | unittest 1555 | { 1556 | alias orghrf = orghr!float; 1557 | alias orghrd = orghr!double; 1558 | alias unghrf = unghr!float; 1559 | alias unghrd = unghr!double; 1560 | alias unghrcf = unghr!_cfloat; 1561 | alias unghrcd = unghr!_cdouble; 1562 | } 1563 | 1564 | /// 1565 | size_t gehrd(T)( 1566 | Slice!(T*, 2, Canonical) a, 1567 | Slice!(T*) tau, 1568 | Slice!(T*) work, 1569 | lapackint ilo, 1570 | lapackint ihi 1571 | ) 1572 | in 1573 | { 1574 | assert(a.length!1 >= a.length!0, "gehrd: The number of columns of 'a' must be greater than or equal to the number of its rows."); //m>=n 1575 | assert(a.length!0 >= tau.length, "gehrd: The number of columns of 'a' must be greater than or equal to the length of 'tau'."); //n>=k 1576 | assert(work.length >= a.length!0, "gehrd: The length of 'work' must be greater than or equal to the number of rows of 'a'."); //lwork>=n 1577 | } 1578 | do 1579 | { 1580 | lapackint n = cast(lapackint) a.length!0; 1581 | lapackint lda = cast(lapackint) a._stride.max(1); 1582 | lapackint lwork = cast(lapackint) work.length; 1583 | lapackint info; 1584 | lapack.gehrd_(n, ilo, ihi, a.iterator, lda, tau.iterator, work.iterator, lwork, info); 1585 | ///if info == 0: successful exit. 1586 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 1587 | assert(info >= 0); 1588 | return cast(size_t)info; 1589 | } 1590 | 1591 | unittest 1592 | { 1593 | alias s = gehrd!_cfloat; 1594 | alias d = gehrd!_cdouble; 1595 | } 1596 | 1597 | size_t hsein(T)( 1598 | char side, 1599 | char eigsrc, 1600 | char initv, 1601 | ref lapackint select, //actually a logical bitset stored in here 1602 | Slice!(T*, 2, Canonical) h, 1603 | Slice!(T*) wr, 1604 | Slice!(T*) wi, 1605 | Slice!(T*, 2, Canonical) vl, 1606 | Slice!(T*, 2, Canonical) vr, 1607 | ref lapackint m, 1608 | Slice!(T*) work, 1609 | ref lapackint ifaill, 1610 | ref lapackint ifailr, 1611 | ) 1612 | if (!isComplex!T) 1613 | in 1614 | { 1615 | assert(h.length!1 >= h.length!0, "hsein: The number of columns of 'h' " ~ 1616 | "must be greater than or equal to the number of its rows."); //m>=n 1617 | assert(wr.length >= 1, "hsein: The input 'wr' must have length greater " ~ 1618 | "than or equal to one."); 1619 | assert(wr.length >= h.length!0, "hsein: The input 'wr' must have length greater " ~ 1620 | "than or equal to the number of rows of 'h'."); 1621 | assert(wr.length >= 1.0, "hsein: The input 'wr' must have length greater " ~ 1622 | "than or equal to 1."); 1623 | assert(wi.length >= 1, "hsein: The input 'wi' must have length greater " ~ 1624 | "than or equal to one."); 1625 | assert(wi.length >= h.length!0, "hsein: The input 'wi' must have length greater " ~ 1626 | "than or equal to the number of rows of 'h'."); 1627 | assert(wi.length >= 1.0, "hsein: The input 'wi' must have length greater " ~ 1628 | "than or equal to 1."); 1629 | assert(work.length >= h.length!0 * (h.length!0 + 2), "hsein: The length of 'work' must be " ~ 1630 | "greater than or equal to the square of the number of rows of 'h' plus two additional rows for real types."); 1631 | assert(side == 'R' || side == 'L' || side == 'B', "hsein: The char, 'side' must be " ~ 1632 | "one of 'R', 'L' or 'B'."); 1633 | assert(eigsrc == 'Q' || eigsrc == 'N', "hsein: The char, 'eigsrc', must be " ~ 1634 | "one of 'Q' or 'R'."); 1635 | assert(initv == 'N' || initv == 'U', "hsein: The char, 'initv', must be " ~ 1636 | "one of 'N' or 'U'."); 1637 | assert(side != 'L' || side != 'B' || vl.length!1 >= 1, "hsein: Slice 'vl' must be" ~ 1638 | "at least the size of '1' when 'side' is set to 'L' or 'B'."); 1639 | assert(side != 'R' || vl.length!1 >= 1, "hsein: Slice 'vl' must be" ~ 1640 | "length greater than 1 when 'side' is 'R'."); 1641 | assert(side != 'R' || side != 'B' || vr.length!1 >= 1, "hsein: Slice 'vr' must be" ~ 1642 | "at least the size of '1' when 'side' is set to 'R' or 'B'."); 1643 | assert(side != 'L' || vl.length!1 >= 1, "hsein: Slice 'vr' must be" ~ 1644 | "length greater than 1 when 'side' is 'L'."); 1645 | } 1646 | do 1647 | { 1648 | lapackint info; 1649 | lapackint mm = cast(lapackint) vl.length!1; 1650 | lapackint n = cast(lapackint) h.length!0; 1651 | lapackint ldh = cast(lapackint) h._stride.max(1); 1652 | lapackint ldvl = cast(lapackint) vl._stride.max(1); 1653 | lapackint ldvr = cast(lapackint) vr._stride.max(1); 1654 | //need to seperate these methods then probably provide a wrap which does this as that's the easiest way without bloating the base methods 1655 | lapack.hsein_(side, eigsrc, initv, select, n, h.iterator, ldh, wr.iterator, wi.iterator, vl.iterator, ldvl, vr.iterator, ldvr, mm, m, work.iterator, ifaill, ifailr, info); 1656 | assert(info >= 0); 1657 | ///if any of ifaill or ifailr entries are non-zero then that has failed to converge. 1658 | ///ifail?[i] = j > 0 if the eigenvector stored in the i-th column of v?, coresponding to the jth eigenvalue, fails to converge. 1659 | assert(ifaill == 0); 1660 | assert(ifailr == 0); 1661 | return info; 1662 | } 1663 | 1664 | size_t hsein(T, realT)( 1665 | char side, 1666 | char eigsrc, 1667 | char initv, 1668 | lapackint select, //actually a logical bitset stored in here 1669 | Slice!(T*, 2, Canonical) h, 1670 | Slice!(T*) w, 1671 | Slice!(T*, 2, Canonical) vl, 1672 | Slice!(T*, 2, Canonical) vr, 1673 | lapackint* m, 1674 | Slice!(T*) work, 1675 | Slice!(realT*) rwork, 1676 | lapackint ifaill, 1677 | lapackint ifailr, 1678 | ) 1679 | if (isComplex!T && is(realType!T == realT)) 1680 | in 1681 | { 1682 | assert(h.length!1 >= h.length!0, "hsein: The number of columns of 'h' " ~ 1683 | "must be greater than or equal to the number of its rows."); //m>=n 1684 | assert(w.length >= 1, "hsein: The input 'w' must have length greater " ~ 1685 | "than or equal to one."); 1686 | assert(w.length >= h.length!0, "hsein: The input 'w' must have length greater " ~ 1687 | "than or equal to the number of rows of 'h'."); 1688 | assert(w.length >= 1.0, "hsein: The input 'w' must have length greater " ~ 1689 | "than or equal to 1."); 1690 | assert(work.length >= h.length!0 * h.length!0, "hsein: The length of 'work' must be " ~ 1691 | "greater than or equal to the square of the number of rows of 'h' for complex types."); 1692 | assert(side == 'R' || side == 'L' || side == 'B', "hsein: The char, 'side' must be " ~ 1693 | "one of 'R', 'L' or 'B'."); 1694 | assert(eigsrc == 'Q' || eigsrc == 'N', "hsein: The char, 'eigsrc', must be " ~ 1695 | "one of 'Q' or 'R'."); 1696 | assert(initv == 'N' || initv == 'U', "hsein: The char, 'initv', must be " ~ 1697 | "one of 'N' or 'U'."); 1698 | assert(side != 'L' || side != 'B' || vl.length!1 >= 1, "hsein: Slice 'vl' must be" ~ 1699 | "at least the size of '1' when 'side' is set to 'L' or 'B'."); 1700 | assert(side != 'R' || vl.length!1 >= 1, "hsein: Slice 'vl' must be" ~ 1701 | "length greater than 1 when 'side' is 'R'."); 1702 | assert(side != 'R' || side != 'B' || vr.length!1 >= 1, "hsein: Slice 'vr' must be" ~ 1703 | "at least the size of '1' when 'side' is set to 'R' or 'B'."); 1704 | assert(side != 'L' || vl.length!1 >= 1, "hsein: Slice 'vr' must be" ~ 1705 | "length greater than 1 when 'side' is 'L'."); 1706 | } 1707 | do { 1708 | lapackint n = cast(lapackint) h.length!0; 1709 | lapackint ldh = cast(lapackint) h._stride.max(1); 1710 | lapackint ldvl = cast(lapackint) vl._stride.max(1); 1711 | lapackint ldvr = cast(lapackint) vr._stride.max(1); 1712 | lapackint mm = cast(lapackint) vl.length!1; 1713 | lapackint info; 1714 | //could compute mm and m from vl and/or vr and T 1715 | lapack.hsein_(side, eigsrc, initv, select, n, h.iterator, ldh, w.iterator, vl.iterator, ldvl, vr.iterator, ldvr, mm, *m, work.iterator, rwork.iterator, ifaill, ifailr, info); 1716 | assert(info >= 0); 1717 | ///if any of ifaill or ifailr entries are non-zero then that has failed to converge. 1718 | ///ifail?[i] = j > 0 if the eigenvector stored in the i-th column of v?, coresponding to the jth eigenvalue, fails to converge. 1719 | assert(ifaill == 0); 1720 | assert(ifailr == 0); 1721 | return info; 1722 | } 1723 | 1724 | 1725 | unittest 1726 | { 1727 | alias f = hsein!(float); 1728 | alias d = hsein!(double); 1729 | alias s = hsein!(_cfloat, float); 1730 | alias c = hsein!(_cdouble, double); 1731 | } 1732 | 1733 | alias ormhr = unmhr; 1734 | 1735 | /// 1736 | size_t unmhr(T)( 1737 | char side, 1738 | char trans, 1739 | Slice!(T*, 2, Canonical) a, 1740 | Slice!(T*) tau, 1741 | Slice!(T*, 2, Canonical) c, 1742 | Slice!(T*) work, 1743 | lapackint ilo, 1744 | lapackint ihi 1745 | ) 1746 | in 1747 | { 1748 | assert(a.length!0 >= 0, "ormhr: The number of columns of 'a' must be " ~ 1749 | "greater than or equal to zero."); //n>=0 1750 | assert(a.length!1 >= a.length!0, "ormhr: The number of columns of 'a' " ~ 1751 | "must be greater than or equal to the number of its rows."); //m>=n 1752 | assert(c.length!0 >= 0, "ormhr: The number of columns of 'c' must be " ~ 1753 | "greater than or equal to zero."); //n>=0 1754 | assert(c.length!1 >= c.length!0, "ormhr: The number of columns of 'c' " ~ 1755 | "must be greater than or equal to the number of its rows."); //m>=n 1756 | assert(tau.length >= 0, "ormhr: The input 'tau' must have length greater " ~ 1757 | "than or equal to zero."); //k>=0 1758 | assert(a.length!0 >= tau.length, "ormhr: The number of columns of 'a' " ~ 1759 | "must be greater than or equal to the length of 'tau'."); //n>=k 1760 | assert(work.length >= a.length!0, "ormhr: The length of 'work' must be " ~ 1761 | "greater than or equal to the number of rows of 'a'."); //lwork>=n 1762 | assert(side == 'L' || side == 'R', "ormhr: 'side' must be" ~ 1763 | "one of 'L' or 'R'."); 1764 | assert(trans == 'N' || trans == 'T', "ormhr: 'trans' must be" ~ 1765 | "one of 'N' or 'T'."); 1766 | } 1767 | do 1768 | { 1769 | lapackint m = cast(lapackint) a.length!0; 1770 | lapackint n = cast(lapackint) a.length!1; 1771 | lapackint lda = cast(lapackint) a._stride.max(1); 1772 | lapackint ldc = cast(lapackint) c._stride.max(1); 1773 | lapackint lwork = cast(lapackint) work.length; 1774 | lapackint info; 1775 | static if (!isComplex!T){ 1776 | lapack.ormhr_(side, trans, m, n, ilo, ihi, a.iterator, lda, tau.iterator, c.iterator, ldc, work.iterator, lwork, info); 1777 | } 1778 | else { 1779 | lapack.unmhr_(side, trans, m, n, ilo, ihi, a.iterator, lda, tau.iterator, c.iterator, ldc, work.iterator, lwork, info); 1780 | } 1781 | ///if info == 0: successful exit. 1782 | ///if info < 0: if info == -i, the i-th argument had an illegal value. 1783 | assert(info >= 0); 1784 | return cast(size_t)info; 1785 | } 1786 | 1787 | unittest 1788 | { 1789 | alias s = unmhr!_cfloat; 1790 | alias d = unmhr!_cdouble; 1791 | alias a = ormhr!double; 1792 | alias b = ormhr!float; 1793 | } 1794 | 1795 | /// 1796 | size_t hseqr(T)( 1797 | char job, 1798 | char compz, 1799 | Slice!(T*, 2, Canonical) h, 1800 | Slice!(T*) w, 1801 | Slice!(T*, 2, Canonical) z, 1802 | Slice!(T*) work, 1803 | lapackint ilo, 1804 | lapackint ihi 1805 | ) 1806 | if (isComplex!T) 1807 | in 1808 | { 1809 | assert(job == 'E' || job == 'S', "hseqr"); 1810 | assert(compz == 'N' || compz == 'I' || compz == 'V', "hseqr"); 1811 | assert(h.length!1 >= h.length!0, "hseqr"); 1812 | assert(h.length!1 >= 1, "hseqr"); 1813 | assert(compz != 'V' || compz != 'I' || (z.length!1 >= h.length!0 && z.length!1 >= 1), "hseqr"); 1814 | assert(compz != 'N' || z.length!1 >= 1); 1815 | assert(work.length!0 >= 1, "hseqr"); 1816 | assert(work.length!0 >= h.length!0, "hseqr"); 1817 | } 1818 | do 1819 | { 1820 | lapackint n = cast(lapackint) h.length!0; 1821 | lapackint ldh = cast(lapackint) h._stride.max(1); 1822 | lapackint ldz = cast(lapackint) z._stride.max(1); 1823 | lapackint lwork = cast(lapackint) work.length!0; 1824 | lapackint info; 1825 | lapack.hseqr_(job,compz,n,ilo,ihi,h.iterator, ldh, w.iterator, z.iterator, ldz, work.iterator, lwork, info); 1826 | assert(info >= 0); 1827 | return cast(size_t)info; 1828 | } 1829 | 1830 | /// 1831 | size_t hseqr(T)( 1832 | char job, 1833 | char compz, 1834 | Slice!(T*, 2, Canonical) h, 1835 | Slice!(T*) wr, 1836 | Slice!(T*) wi, 1837 | Slice!(T*, 2, Canonical) z, 1838 | Slice!(T*) work, 1839 | lapackint ilo, 1840 | lapackint ihi 1841 | ) 1842 | if (!isComplex!T) 1843 | in 1844 | { 1845 | assert(job == 'E' || job == 'S', "hseqr"); 1846 | assert(compz == 'N' || compz == 'I' || compz == 'V', "hseqr"); 1847 | assert(h.length!1 >= h.length!0, "hseqr"); 1848 | assert(h.length!1 >= 1, "hseqr"); 1849 | assert(compz != 'V' || compz != 'I' || (z.length!1 >= h.length!0 && z.length!1 >= 1), "hseqr"); 1850 | assert(compz != 'N' || z.length!1 >= 1); 1851 | assert(work.length!0 >= 1, "hseqr"); 1852 | assert(work.length!0 >= h.length!0, "hseqr"); 1853 | } 1854 | do 1855 | { 1856 | lapackint n = cast(lapackint) h.length!0; 1857 | lapackint ldh = cast(lapackint) h._stride.max(1); 1858 | lapackint ldz = cast(lapackint) z._stride.max(1); 1859 | lapackint lwork = cast(lapackint) work.length!0; 1860 | lapackint info; 1861 | lapack.hseqr_(job,compz,n,ilo,ihi,h.iterator, ldh, wr.iterator, wi.iterator, z.iterator, ldz, work.iterator, lwork, info); 1862 | assert(info >= 0); 1863 | return cast(size_t)info; 1864 | } 1865 | 1866 | unittest 1867 | { 1868 | alias f = hseqr!float; 1869 | alias d = hseqr!double; 1870 | alias s = hseqr!_cfloat; 1871 | alias c = hseqr!_cdouble; 1872 | } 1873 | 1874 | /// 1875 | size_t trevc(T)(char side, 1876 | char howmany, 1877 | lapackint select, 1878 | Slice!(T*, 2, Canonical) t, 1879 | Slice!(T*, 2, Canonical) vl, 1880 | Slice!(T*, 2, Canonical) vr, 1881 | lapackint m, 1882 | Slice!(T*) work 1883 | ) 1884 | do 1885 | { 1886 | lapackint n = cast(lapackint)t.length!0; 1887 | lapackint ldt = cast(lapackint) t._stride.max(1); 1888 | lapackint ldvl = cast(lapackint) vl._stride.max(1); 1889 | lapackint ldvr = cast(lapackint) vr._stride.max(1); 1890 | lapackint mm = cast(lapackint) vr.length!1; 1891 | //select should be lapack_logical 1892 | lapackint info; 1893 | static if(!isComplex!T){ 1894 | lapack.trevc_(side, howmany, select, n, t.iterator, ldt, vl.iterator, ldvl, vr.iterator, ldvr, mm, m, work.iterator, info); 1895 | } 1896 | else { 1897 | lapack.trevc_(side, howmany, select, n, t.iterator, ldt, vl.iterator, ldvl, vr.iterator, ldvr, mm, m, work.iterator, null, info); 1898 | } 1899 | assert(info >= 0); 1900 | return cast(size_t)info; 1901 | } 1902 | 1903 | unittest 1904 | { 1905 | alias f = trevc!float; 1906 | alias d = trevc!double; 1907 | alias s = trevc!_cfloat; 1908 | alias c = trevc!_cdouble; 1909 | } 1910 | 1911 | /// 1912 | size_t gebal(T, realT)(char job, 1913 | Slice!(T*, 2, Canonical) a, 1914 | lapackint ilo, 1915 | lapackint ihi, 1916 | Slice!(realT*) scale 1917 | ) 1918 | if (!isComplex!T || (isComplex!T && is(realType!T == realT))) 1919 | { 1920 | lapackint n = cast(lapackint) a.length!0; 1921 | lapackint lda = cast(lapackint) a._stride.max(1); 1922 | lapackint info; 1923 | lapack.gebal_(job, n, a.iterator, lda, ilo, ihi, scale.iterator, info); 1924 | assert(info >= 0); 1925 | return cast(size_t)info; 1926 | } 1927 | 1928 | unittest 1929 | { 1930 | alias a = gebal!(double, double); 1931 | alias b = gebal!(_cdouble, double); 1932 | alias c = gebal!(float, float); 1933 | alias d = gebal!(_cfloat, float); 1934 | } 1935 | 1936 | /// 1937 | size_t gebak(T, realT)( 1938 | char job, 1939 | char side, 1940 | lapackint ilo, 1941 | lapackint ihi, 1942 | Slice!(realT*) scale, 1943 | Slice!(T*, 2, Canonical) v 1944 | ) 1945 | if (!isComplex!T || (isComplex!T && is(realType!T == realT))) 1946 | { 1947 | lapackint n = cast(lapackint) scale.length!0; 1948 | lapackint m = cast(lapackint) v.length!1;//num evects 1949 | lapackint ldv = cast(lapackint) v._stride.max(1); 1950 | lapackint info; 1951 | lapack.gebak_(job, side, n, ilo, ihi, scale.iterator, m, v.iterator, ldv, info); 1952 | assert(info >= 0); 1953 | return cast(size_t)info; 1954 | } 1955 | 1956 | unittest 1957 | { 1958 | alias a = gebak!(double, double); 1959 | alias b = gebak!(_cdouble, double); 1960 | alias c = gebak!(float, float); 1961 | alias d = gebak!(_cfloat, float); 1962 | } 1963 | 1964 | /// 1965 | size_t geev(T, realT)( 1966 | char jobvl, 1967 | char jobvr, 1968 | Slice!(T*, 2, Canonical) a, 1969 | Slice!(T*) w, 1970 | Slice!(T*, 2, Canonical) vl, 1971 | Slice!(T*, 2, Canonical) vr, 1972 | Slice!(T*) work, 1973 | Slice!(realT*) rwork 1974 | ) 1975 | if (isComplex!T && is(realType!T == realT)) 1976 | { 1977 | lapackint n = cast(lapackint) a.length!0; 1978 | lapackint lda = cast(lapackint) a._stride.max(1); 1979 | lapackint ldvr = cast(lapackint) vr._stride.max(1); 1980 | lapackint ldvl = cast(lapackint) vl._stride.max(1); 1981 | lapackint info; 1982 | lapackint lwork = cast(lapackint)work.length!0; 1983 | lapack.geev_(jobvl, jobvr, n, a.iterator, lda, w.iterator, vl.iterator, ldvl, vr.iterator, ldvr, work.iterator, lwork, rwork.iterator, info); 1984 | assert(info >= 0); 1985 | return info; 1986 | } 1987 | 1988 | /// 1989 | size_t geev(T)( 1990 | char jobvl, 1991 | char jobvr, 1992 | Slice!(T*, 2, Canonical) a, 1993 | Slice!(T*) wr, 1994 | Slice!(T*) wi, 1995 | Slice!(T*, 2, Canonical) vl, 1996 | Slice!(T*, 2, Canonical) vr, 1997 | Slice!(T*) work 1998 | ) 1999 | if (!isComplex!T) 2000 | { 2001 | lapackint n = cast(lapackint) a.length!0; 2002 | lapackint lda = cast(lapackint) a._stride.max(1); 2003 | lapackint ldvr = cast(lapackint) vr._stride.max(1); 2004 | lapackint ldvl = cast(lapackint) vl._stride.max(1); 2005 | lapackint info; 2006 | lapackint lwork = cast(lapackint)work.length!0; 2007 | lapack.geev_(jobvl, jobvr, n, a.iterator, lda, wr.iterator, wi.iterator, vl.iterator, ldvl, vr.iterator, ldvr, work.iterator, lwork, info); 2008 | assert(info >= 0); 2009 | return info; 2010 | } 2011 | 2012 | /// 2013 | size_t steqr(T, realT = realType!T)( 2014 | char compz, 2015 | Slice!(realT*) d, 2016 | Slice!(realT*) e, 2017 | Slice!(T*, 2, Canonical) z, 2018 | Slice!(realT*) work) 2019 | if (is(realType!T == realT)) 2020 | in { 2021 | assert(d.length == e.length + 1); 2022 | assert(work.length >= (e.length * 2).max(1u)); 2023 | assert(z.length!0 == d.length); 2024 | assert(z.length!1 == d.length); 2025 | assert(z._stride >= d.length); 2026 | } 2027 | do { 2028 | lapackint n = cast(lapackint) d.length; 2029 | lapackint ldz = cast(lapackint) z._stride.max(1); 2030 | lapackint info; 2031 | 2032 | lapack.steqr_(compz, n, d.iterator, e.iterator, z.iterator, ldz, work.iterator, info); 2033 | assert(info >= 0); 2034 | return info; 2035 | } 2036 | 2037 | unittest 2038 | { 2039 | alias a = steqr!float; 2040 | alias b = steqr!double; 2041 | alias c = steqr!_cfloat; 2042 | alias d = steqr!_cdouble; 2043 | } 2044 | 2045 | 2046 | /// 2047 | @trusted 2048 | size_t sytrs_3(T)( 2049 | char uplo, 2050 | Slice!(const(T)*, 2, Canonical) a, 2051 | Slice!(const(T)*) e, 2052 | Slice!(const(lapackint)*) ipiv, 2053 | Slice!(T*, 2, Canonical) b, 2054 | ) 2055 | in 2056 | { 2057 | assert(a.length!0 == a.length!1, "sytrs_3: 'a' must be a square matrix."); 2058 | assert(e.length == a.length, "sytrs_3: 'e' must have the same length as 'a'."); 2059 | assert(b.length!1 == a.length, "sytrs_3: 'b.length!1' must must be equal to 'a.length'."); 2060 | } 2061 | do 2062 | { 2063 | lapackint n = cast(lapackint) a.length; 2064 | lapackint nrhs = cast(lapackint) b.length; 2065 | lapackint lda = cast(lapackint) a._stride.max(1); 2066 | lapackint ldb = cast(lapackint) b._stride.max(1); 2067 | lapackint info; 2068 | // ref char uplo, ref lapackint n, ref lapackint nrhs, float *a, ref lapackint lda, float* e, lapackint *ipiv, float *b, ref lapackint ldb, ref lapackint info 2069 | lapack.sytrs_3_(uplo, n, nrhs, a.iterator, lda, e.iterator, ipiv.iterator, b.iterator, ldb, info); 2070 | assert(info >= 0); 2071 | return info; 2072 | } 2073 | 2074 | version(none) 2075 | unittest 2076 | { 2077 | alias s = sytrs_3!float; 2078 | alias d = sytrs_3!double; 2079 | alias c = sytrs_3!_cfloat; 2080 | alias z = sytrs_3!_cdouble; 2081 | } 2082 | 2083 | /// 2084 | @trusted 2085 | size_t sytrf_rk(T)( 2086 | char uplo, 2087 | Slice!(T*, 2, Canonical) a, 2088 | Slice!(T*) e, 2089 | Slice!(lapackint*) ipiv, 2090 | Slice!(T*) work, 2091 | ) 2092 | in 2093 | { 2094 | assert(a.length!0 == a.length!1, "sytrf_rk: 'a' must be a square matrix."); 2095 | assert(e.length == a.length, "sytrf_rk: 'e' must have the same length as 'a'."); 2096 | } 2097 | do 2098 | { 2099 | lapackint info; 2100 | lapackint n = cast(lapackint) a.length; 2101 | lapackint lda = cast(lapackint) a._stride.max(1); 2102 | lapackint lwork = cast(lapackint) work.length; 2103 | lapack.sytrf_rk_(uplo, n, a.iterator, lda, e.iterator, ipiv.iterator, work.iterator, lwork, info); 2104 | assert(info >= 0); 2105 | return info; 2106 | } 2107 | 2108 | version(none) 2109 | unittest 2110 | { 2111 | alias s = sytrf_rk!float; 2112 | alias d = sytrf_rk!double; 2113 | alias c = sytrf_rk!_cfloat; 2114 | alias z = sytrf_rk!_cdouble; 2115 | } 2116 | 2117 | 2118 | /// 2119 | size_t sytrf_rk_wk(T)( 2120 | char uplo, 2121 | Slice!(T*, 2, Canonical) a, 2122 | ) 2123 | in 2124 | { 2125 | assert(a.length!0 == a.length!1, "sytrf_rk_wk: 'a' must be a square matrix."); 2126 | } 2127 | do 2128 | { 2129 | 2130 | lapackint info; 2131 | lapackint n = cast(lapackint) a.length; 2132 | lapackint lda = cast(lapackint) a._stride.max(1); 2133 | lapackint lwork = -1; 2134 | lapackint info; 2135 | T e; 2136 | T work; 2137 | lapackint ipiv; 2138 | 2139 | lapack.sytrf_rk_(uplo, n, a.iterator, lda, &e, &ipiv, &work, lwork, info); 2140 | 2141 | return cast(size_t) work.re; 2142 | } 2143 | 2144 | version(none) 2145 | unittest 2146 | { 2147 | alias s = sytrf_rk!float; 2148 | alias d = sytrf_rk!double; 2149 | } 2150 | 2151 | /// 2152 | template posvx(T) 2153 | if (is(T == double) || is(T == float)) 2154 | { 2155 | @trusted 2156 | size_t posvx( 2157 | char fact, 2158 | char uplo, 2159 | Slice!(T*, 2, Canonical) a, 2160 | Slice!(T*, 2, Canonical) af, 2161 | char equed, 2162 | Slice!(T*) s, 2163 | Slice!(T*, 2, Canonical) b, 2164 | Slice!(T*, 2, Canonical) x, 2165 | out T rcond, 2166 | Slice!(T*) ferr, 2167 | Slice!(T*) berr, 2168 | Slice!(T*) work, 2169 | Slice!(lapackint*) iwork, 2170 | ) 2171 | in { 2172 | assert(fact == 'F' || fact == 'N' || fact == 'E'); 2173 | assert(uplo == 'U' || uplo == 'L'); 2174 | auto n = a.length!0; 2175 | auto nrhs = x.length; 2176 | assert(a.length!1 == n); 2177 | assert(af.length!0 == n); 2178 | assert(af.length!1 == n); 2179 | assert(x.length!1 == n); 2180 | assert(b.length!1 == n); 2181 | assert(b.length!0 == nrhs); 2182 | assert(ferr.length == nrhs); 2183 | assert(berr.length == nrhs); 2184 | assert(work.length == n * 3); 2185 | assert(iwork.length == n); 2186 | } 2187 | do { 2188 | lapackint n = cast(lapackint) a.length!0; 2189 | lapackint nrhs = cast(lapackint) x.length; 2190 | lapackint lda = cast(lapackint) a._stride.max(1); 2191 | lapackint ldaf = cast(lapackint) af._stride.max(1); 2192 | lapackint ldx = cast(lapackint) x._stride.max(1); 2193 | lapackint ldb = cast(lapackint) b._stride.max(1); 2194 | lapackint info; 2195 | lapack.posvx_(fact, uplo, n, nrhs, a._iterator, lda, af._iterator, ldaf, equed, s._iterator, b._iterator, ldb, x._iterator, ldx, rcond, ferr._iterator, berr._iterator, work._iterator, iwork._iterator, info); 2196 | assert(info >= 0); 2197 | return info; 2198 | } 2199 | 2200 | @trusted 2201 | size_t posvx( 2202 | char fact, 2203 | char uplo, 2204 | Slice!(T*, 2, Canonical) a, 2205 | Slice!(T*, 2, Canonical) af, 2206 | char equed, 2207 | Slice!(T*) s, 2208 | Slice!(T*) b, 2209 | Slice!(T*) x, 2210 | out T rcond, 2211 | out T ferr, 2212 | out T berr, 2213 | Slice!(T*) work, 2214 | Slice!(lapackint*) iwork, 2215 | ) 2216 | in { 2217 | assert(fact == 'F' || fact == 'N' || fact == 'E'); 2218 | assert(uplo == 'U' || uplo == 'L'); 2219 | auto n = a.length!0; 2220 | assert(a.length!1 == n); 2221 | assert(af.length!0 == n); 2222 | assert(af.length!1 == n); 2223 | assert(x.length == n); 2224 | assert(b.length == n); 2225 | assert(work.length == n * 3); 2226 | assert(iwork.length == n); 2227 | } 2228 | do { 2229 | import mir.ndslice.topology: canonical; 2230 | return posvx(fact, uplo, a, af, equed, s, b.sliced(1, b.length).canonical, x.sliced(1, x.length).canonical, rcond, sliced(&ferr, 1), sliced(&berr, 1), work, iwork); 2231 | } 2232 | } 2233 | 2234 | version(none) 2235 | unittest 2236 | { 2237 | alias s = posvx!float; 2238 | alias d = posvx!double; 2239 | } 2240 | 2241 | /// 2242 | size_t sytrf_wk(T)( 2243 | char uplo, 2244 | Slice!(T*, 2, Canonical) a, 2245 | ) 2246 | in 2247 | { 2248 | assert(a.length!0 == a.length!1, "sytrf_wk: 'a' must be a square matrix."); 2249 | } 2250 | do 2251 | { 2252 | lapackint n = cast(lapackint) a.length; 2253 | lapackint lda = cast(lapackint) a._stride.max(1); 2254 | lapackint lwork = -1; 2255 | lapackint info; 2256 | T work; 2257 | lapackint ipiv; 2258 | 2259 | lapack.sytrf_(uplo, n, a.iterator, lda, &ipiv, &work, lwork, info); 2260 | 2261 | return cast(size_t) work.re; 2262 | } 2263 | 2264 | unittest 2265 | { 2266 | alias s = sytrf_wk!float; 2267 | alias d = sytrf_wk!double; 2268 | } 2269 | 2270 | /// 2271 | template posv(T) 2272 | if (is(T == double) || is(T == float)) 2273 | { 2274 | @trusted 2275 | size_t posv( 2276 | char uplo, 2277 | Slice!(T*, 2, Canonical) a, 2278 | Slice!(T*, 2, Canonical) b 2279 | ) 2280 | in { 2281 | assert(uplo == 'U' || uplo == 'L'); 2282 | auto n = a.length!0; 2283 | auto nrhs = b.length!0; 2284 | assert(a.length!1 == n); 2285 | assert(b.length!1 == n); 2286 | assert(b.length!0 == nrhs); 2287 | } 2288 | do { 2289 | lapackint n = cast(lapackint) a.length!0; 2290 | lapackint nrhs = cast(lapackint) b.length!0; 2291 | lapackint lda = cast(lapackint) a._stride.max(1); 2292 | lapackint ldb = cast(lapackint) b._stride.max(1); 2293 | lapackint info; 2294 | lapack.posv_(uplo, n, nrhs, a._iterator, lda, b._iterator, ldb, info); 2295 | assert(info >= 0); 2296 | return info; 2297 | } 2298 | 2299 | @trusted 2300 | size_t posv( 2301 | char uplo, 2302 | Slice!(T*, 2, Canonical) a, 2303 | Slice!(T*) b 2304 | ) 2305 | in { 2306 | assert(uplo == 'U' || uplo == 'L'); 2307 | assert(a.length!0 == a.length!1); 2308 | assert(b.length == a.length!0); 2309 | } 2310 | do { 2311 | import mir.ndslice.topology: canonical; 2312 | return posv(uplo, a, b.sliced(1, b.length).canonical); 2313 | } 2314 | } 2315 | 2316 | version(none) 2317 | unittest 2318 | { 2319 | alias s = posv!float; 2320 | alias d = posv!double; 2321 | } 2322 | --------------------------------------------------------------------------------