├── .gitignore ├── CSparse.Benchmark ├── Benchmark │ ├── Benchmark.cs │ ├── BenchmarkResult.cs │ ├── IBenchmarkResultWriter.cs │ ├── JsonExport.cs │ └── MatrixFileCollection.cs ├── CSparse.Benchmark.csproj ├── Double │ ├── BenchmarkRunner.cs │ ├── Benchmarks │ │ ├── BenchmarkCholmod.cs │ │ ├── BenchmarkPardiso.cs │ │ ├── BenchmarkSuperLU.cs │ │ └── BenchmarkUmfpack.cs │ ├── Helper.cs │ └── SparseMatrixExtensions.cs ├── Examples │ ├── Complex │ │ ├── Generate.cs │ │ └── TestArpack.cs │ ├── Double │ │ ├── Generate.cs │ │ ├── TestArpack.cs │ │ └── TestSpectra.cs │ └── Solution.cs ├── Program.cs ├── StorageExtensions.cs └── benchmark.lst ├── CSparse.Interop.Tests ├── AMD │ ├── TestAMD.cs │ ├── TestCOLAMD.cs │ └── TestRunner.cs ├── CSparse.Interop.Tests.csproj ├── Complex │ ├── EigenSolvers │ │ ├── TestArpack.cs │ │ └── TestFeast.cs │ ├── Generate.cs │ ├── Helper.cs │ ├── TestBase.cs │ ├── TestCXSparseCholesky.cs │ ├── TestCXSparseLU.cs │ ├── TestCXSparseQR.cs │ ├── TestCholmod.cs │ ├── TestCuda.cs │ ├── TestPardiso.cs │ ├── TestRunner.cs │ ├── TestSPQR.cs │ ├── TestSparseCholesky.cs │ ├── TestSparseLU.cs │ ├── TestSparseQR.cs │ ├── TestSuperLU.cs │ └── TestUmfpack.cs ├── Config.cs ├── Display.cs ├── Double │ ├── EigenSolvers │ │ ├── TestArpack.cs │ │ ├── TestExtendedEigensolver.cs │ │ ├── TestFeast.cs │ │ └── TestSpectra.cs │ ├── Generate.cs │ ├── Helper.cs │ ├── SparseMatrixExtensions.cs │ ├── TestBase.cs │ ├── TestCXSparseCholesky.cs │ ├── TestCXSparseLU.cs │ ├── TestCXSparseQR.cs │ ├── TestCholmod.cs │ ├── TestCuda.cs │ ├── TestPardiso.cs │ ├── TestRunner.cs │ ├── TestSPQR.cs │ ├── TestSparseCholesky.cs │ ├── TestSparseLU.cs │ ├── TestSparseQR.cs │ ├── TestSparseQR_MKL.cs │ ├── TestSuperLU.cs │ └── TestUmfpack.cs └── Program.cs ├── CSparse.Interop.sln ├── CSparse.Interop ├── CSparse.Interop.csproj ├── Complex │ ├── Factorization │ │ ├── CUDA │ │ │ ├── CudaCholesky.cs │ │ │ └── CudaQR.cs │ │ ├── MKL │ │ │ └── Pardiso.cs │ │ ├── SuiteSparse │ │ │ ├── CXSparseCholesky.cs │ │ │ ├── CXSparseLU.cs │ │ │ ├── CXSparseQR.cs │ │ │ ├── Cholmod.cs │ │ │ ├── CholmodHelper.cs │ │ │ ├── SPQR.cs │ │ │ └── Umfpack.cs │ │ └── SuperLU.cs │ └── Solver │ │ ├── Arpack.cs │ │ ├── ArpackResult.cs │ │ ├── Feast.cs │ │ └── FeastResult.cs ├── Double │ ├── Factorization │ │ ├── CUDA │ │ │ ├── CudaCholesky.cs │ │ │ └── CudaQR.cs │ │ ├── MKL │ │ │ ├── Pardiso.cs │ │ │ └── SparseQR.cs │ │ ├── SuiteSparse │ │ │ ├── CXSparseCholesky.cs │ │ │ ├── CXSparseLU.cs │ │ │ ├── CXSparseQR.cs │ │ │ ├── Cholmod.cs │ │ │ ├── CholmodHelper.cs │ │ │ ├── SPQR.cs │ │ │ └── Umfpack.cs │ │ └── SuperLU.cs │ └── Solver │ │ ├── Arpack.cs │ │ ├── ArpackResult.cs │ │ ├── ExtendedEigensolver.cs │ │ ├── ExtendedEigensolverResult.cs │ │ ├── Feast.cs │ │ ├── FeastResult.cs │ │ ├── Spectra.cs │ │ └── SpectraResult.cs ├── Factorization │ └── IDisposableSolver.cs ├── Interop │ ├── ARPACK │ │ ├── ArpackContext.cs │ │ ├── ArpackException.cs │ │ ├── ArpackResult.cs │ │ └── NativeMethods.cs │ ├── CUDA │ │ ├── CuSolverContext.cs │ │ ├── CuSolverException.cs │ │ ├── CuSparseContext.cs │ │ ├── CuSparseException.cs │ │ ├── Cuda.cs │ │ ├── CudaDevice.cs │ │ ├── CudaException.cs │ │ ├── CudaStream.cs │ │ ├── NativeMethods.cs │ │ └── Types.cs │ ├── Common │ │ └── InteropHelper.cs │ ├── MKL │ │ ├── ExtendedEigensolver │ │ │ ├── ExtendedEigensolverContext.cs │ │ │ └── ExtendedEigensolverResult.cs │ │ ├── Feast │ │ │ ├── FeastContext.cs │ │ │ ├── FeastException.cs │ │ │ ├── FeastOptions.cs │ │ │ ├── FeastResult.cs │ │ │ └── NativeMethods.cs │ │ ├── Helper.cs │ │ ├── NativeMethods.cs │ │ ├── Pardiso │ │ │ ├── Constants.cs │ │ │ ├── NativeMethods.cs │ │ │ ├── PardisoContext.cs │ │ │ ├── PardisoException.cs │ │ │ ├── PardisoMatrixType.cs │ │ │ ├── PardisoOptions.cs │ │ │ └── PardisoOrdering.cs │ │ ├── SparseQR │ │ │ └── SparseQRContext.cs │ │ └── Types.cs │ ├── Metis │ │ ├── Helper.cs │ │ ├── MetisGraph.cs │ │ ├── MetisMesh.cs │ │ ├── MetisOptions.cs │ │ └── NativeMethods.cs │ ├── Spectra │ │ ├── NativeMethods.cs │ │ ├── SpectraContext.cs │ │ ├── SpectraException.cs │ │ └── SpectraResult.cs │ ├── SuiteSparse │ │ ├── CXSparse │ │ │ ├── CXSparseContext.cs │ │ │ └── NativeMethods.cs │ │ ├── Cholmod │ │ │ ├── CholmodCommon.cs │ │ │ ├── CholmodContext.cs │ │ │ ├── CholmodDense.cs │ │ │ ├── CholmodException.cs │ │ │ ├── CholmodFactor.cs │ │ │ ├── CholmodSparse.cs │ │ │ ├── CholmodTriplet.cs │ │ │ ├── Constants.cs │ │ │ └── NativeMethods.cs │ │ ├── Helper.cs │ │ ├── Ordering │ │ │ ├── AMD.cs │ │ │ ├── COLAMD.cs │ │ │ └── SYMAMD.cs │ │ ├── SPQR │ │ │ ├── Constants.cs │ │ │ ├── NativeMethods.cs │ │ │ ├── SpqrContext.cs │ │ │ └── SpqrOrdering.cs │ │ └── Umfpack │ │ │ ├── Constants.cs │ │ │ ├── NativeMethods.cs │ │ │ ├── UmfpackContext.cs │ │ │ ├── UmfpackControl.cs │ │ │ ├── UmfpackException.cs │ │ │ ├── UmfpackInfo.cs │ │ │ └── UmfpackSolve.cs │ └── SuperLU │ │ ├── Constants.cs │ │ ├── NativeMethods.cs │ │ ├── OrderingMethod.cs │ │ ├── SuperLUContext.cs │ │ ├── SuperLUException.cs │ │ ├── SuperLUOptions.cs │ │ └── SuperMatrix.cs ├── Solvers │ ├── IEigenSolver.cs │ ├── IEigenSolverResult.cs │ ├── Job.cs │ ├── ShiftMode.cs │ └── Spectrum.cs └── Storage │ ├── CompressedColumnStorageExtensions.cs │ └── CompressedRowStorage.cs ├── LICENSE └── README.md /CSparse.Benchmark/Benchmark/Benchmark.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Benchmark 3 | { 4 | using CSparse.Double; 5 | using CSparse.Factorization; 6 | using CSparse.IO; 7 | using CSparse.Storage; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Diagnostics; 11 | using System.IO; 12 | 13 | public abstract class Benchmark 14 | where T : struct, IEquatable, IFormattable 15 | { 16 | private MatrixFileCollection collection; 17 | 18 | protected Benchmark(MatrixFileCollection collection) 19 | { 20 | this.collection = collection; 21 | } 22 | 23 | public void Run(IBenchmarkResultWriter export) 24 | { 25 | var timer = new Stopwatch(); 26 | 27 | // Running symmetric tests. 28 | var results = new List(); 29 | 30 | foreach (var file in collection.Get(true)) 31 | { 32 | Run(file, timer, results); 33 | } 34 | 35 | export.Add("symmetric", results); 36 | 37 | // Running non-symmetric tests. 38 | results = new List(); 39 | 40 | foreach (var file in collection.Get(false)) 41 | { 42 | Run(file, timer, results); 43 | } 44 | 45 | export.Add("general", results); 46 | } 47 | 48 | private void Run(MatrixFile file, Stopwatch timer, List results) 49 | { 50 | string name = Path.GetFileName(file.Path); 51 | 52 | if (!File.Exists(file.Path)) 53 | { 54 | results.Add(new BenchmarkResult(file, "File not found.")); 55 | 56 | return; 57 | } 58 | 59 | try 60 | { 61 | var A = (CompressedColumnStorage)file.Matrix; 62 | 63 | if (A == null) 64 | { 65 | A = MatrixMarketReader.ReadMatrix(file.Path); 66 | } 67 | 68 | int columns = A.ColumnCount; 69 | 70 | var x = CreateTestVector(columns); 71 | var s = CreateTestVector(columns); 72 | var b = new T[A.RowCount]; 73 | 74 | A.Multiply(x, b); 75 | 76 | Array.Clear(x, 0, columns); 77 | 78 | var info = new BenchmarkResult(file, A.RowCount, columns, GetNonZerosCount(A)); 79 | 80 | info.Time = Solve(A, b, x, file.Symmetric, timer); 81 | 82 | info.Residual = ComputeError(columns, x, s); 83 | 84 | results.Add(info); 85 | } 86 | catch (Exception e) 87 | { 88 | results.Add(new BenchmarkResult(file, e.Message)); 89 | } 90 | } 91 | 92 | private double Solve(CompressedColumnStorage matrix, T[] input, T[] x, bool symmetric, Stopwatch timer) 93 | { 94 | // Make a copy of the data (the solver might modify it). 95 | var A = matrix.Clone(); 96 | var b = (T[])input.Clone(); 97 | 98 | timer.Restart(); 99 | 100 | using (var solver = CreateSolver(A, symmetric)) 101 | { 102 | solver.Solve(b, x); 103 | } 104 | 105 | timer.Stop(); 106 | 107 | return timer.Elapsed.TotalMilliseconds; 108 | } 109 | 110 | private int GetNonZerosCount(Matrix matrix) 111 | { 112 | return ((CompressedColumnStorage)matrix).NonZerosCount; 113 | } 114 | 115 | protected abstract T[] CreateTestVector(int size); 116 | 117 | protected abstract IDisposableSolver CreateSolver(CompressedColumnStorage matrix, bool symmetric); 118 | 119 | protected abstract double ComputeError(int n, T[] actual, T[] expected); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /CSparse.Benchmark/Benchmark/BenchmarkResult.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace CSparse.Benchmark 3 | { 4 | public class BenchmarkResult 5 | { 6 | public MatrixFile File { get; private set; } 7 | public string Exception { get; private set; } 8 | 9 | public int RowCount { get; private set; } 10 | public int ColumnCount { get; private set; } 11 | public int NonZerosCount { get; private set; } 12 | 13 | public double Time { get; set; } 14 | public double Residual { get; set; } 15 | 16 | public BenchmarkResult(MatrixFile file, int rows, int columns, int nnz) 17 | { 18 | File = file; 19 | 20 | RowCount = rows; 21 | ColumnCount = columns; 22 | NonZerosCount = nnz; 23 | } 24 | 25 | public BenchmarkResult(MatrixFile file, string message) 26 | { 27 | File = file; 28 | Exception = message; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /CSparse.Benchmark/Benchmark/IBenchmarkResultWriter.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace CSparse.Benchmark 3 | { 4 | using System.Collections.Generic; 5 | 6 | public interface IBenchmarkResultWriter 7 | { 8 | void Add(string section, List results); 9 | 10 | void Save(string file); 11 | } 12 | } -------------------------------------------------------------------------------- /CSparse.Benchmark/Benchmark/JsonExport.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace CSparse.Benchmark 3 | { 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Globalization; 7 | using System.IO; 8 | 9 | public class JsonExport : IBenchmarkResultWriter 10 | { 11 | string name; 12 | string info; 13 | 14 | Dictionary> sections; 15 | List> totals; 16 | 17 | public JsonExport(string name, string info) 18 | { 19 | this.name = name; 20 | this.info = info; 21 | 22 | sections = new Dictionary>(); 23 | totals = new List>(); 24 | } 25 | 26 | public void Add(string name, List results) 27 | { 28 | sections[name] = results; 29 | } 30 | 31 | public void Save(string file) 32 | { 33 | using (var writer = new StreamWriter(file)) 34 | { 35 | writer.WriteLine("{"); 36 | 37 | writer.WriteLine("\"name\": \"{0}\",", name); 38 | writer.WriteLine("\"info\": \"{0}\",", info); 39 | 40 | foreach (var section in sections) 41 | { 42 | WriteSection(section.Key, section.Value, writer); 43 | } 44 | 45 | WriteTotal(writer); 46 | 47 | writer.WriteLine("}"); 48 | } 49 | } 50 | 51 | private void WriteTotal(StreamWriter writer) 52 | { 53 | writer.WriteLine("\"total\": ["); 54 | 55 | int count = totals.Count; 56 | 57 | foreach (var tuple in totals) 58 | { 59 | writer.WriteLine(" {{ \"{0}\": {1} }}{2}", 60 | tuple.Item1, tuple.Item2.ToString("0.000", CultureInfo.InvariantCulture), 61 | (--count == 0) ? "" : ","); 62 | } 63 | 64 | writer.WriteLine("]"); 65 | } 66 | 67 | private void WriteSection(string name, List results, StreamWriter writer) 68 | { 69 | double total = 0.0; 70 | 71 | writer.WriteLine("\"{0}\": [", name); 72 | 73 | int count = results.Count; 74 | 75 | foreach (var result in results) 76 | { 77 | WriteResult(result, writer, (--count == 0)); 78 | 79 | total += result.Time; 80 | } 81 | 82 | writer.WriteLine("],"); 83 | 84 | totals.Add(new Tuple(name, total)); 85 | } 86 | 87 | private void WriteResult(BenchmarkResult result, StreamWriter writer, bool last) 88 | { 89 | string name = Path.GetFileName(result.File.Path); 90 | 91 | if (result.Exception != null) 92 | { 93 | writer.WriteLine(" {{ \"file\": \"{0}\", \"exception\": \"{1}\" }},", name, result.Exception); 94 | 95 | return; 96 | } 97 | 98 | writer.WriteLine(" {{ \"file\": \"{0}\", \"size\": {1}, \"values\": {2}, \"time\": {3}, \"error\": {4} }}{5}", 99 | name, result.RowCount, result.NonZerosCount, 100 | result.Time.ToString("0.000", CultureInfo.InvariantCulture), 101 | result.Residual.ToString("0.00000e00", CultureInfo.InvariantCulture), 102 | last ? "" : ","); 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /CSparse.Benchmark/Benchmark/MatrixFileCollection.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Benchmark 3 | { 4 | using CSparse.IO; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | 9 | public class MatrixFile 10 | { 11 | public bool Symmetric { get; set; } 12 | public string Path { get; set; } 13 | public object Matrix { get; set; } 14 | } 15 | 16 | public class MatrixFileCollection 17 | { 18 | private List generalList; 19 | private List symmetricList; 20 | 21 | public MatrixFileCollection(string file, string directory) 22 | { 23 | generalList = new List(); 24 | symmetricList = new List(); 25 | 26 | ReadMatrixFileList(file, directory); 27 | } 28 | 29 | public int Count(bool symmetric) 30 | { 31 | if (symmetric) 32 | { 33 | return symmetricList.Count; 34 | } 35 | 36 | return generalList.Count; 37 | } 38 | 39 | public int Preload() where T : struct, IEquatable, IFormattable 40 | { 41 | int count = 0; 42 | 43 | foreach (var item in generalList) 44 | { 45 | item.Matrix = MatrixMarketReader.ReadMatrix(item.Path); 46 | count++; 47 | } 48 | 49 | foreach (var item in symmetricList) 50 | { 51 | item.Matrix = MatrixMarketReader.ReadMatrix(item.Path); 52 | count++; 53 | } 54 | 55 | return count; 56 | } 57 | 58 | public List Get(bool symmetric) 59 | { 60 | if (symmetric) 61 | { 62 | return symmetricList; 63 | } 64 | 65 | return generalList; 66 | } 67 | 68 | private void ReadMatrixFileList(string file, string directory) 69 | { 70 | if (!File.Exists(file)) 71 | { 72 | throw new Exception("File not found: " + Path.GetFullPath(file)); 73 | } 74 | 75 | using (var reader = new StreamReader(file)) 76 | { 77 | bool symmetric = false; 78 | 79 | while (!reader.EndOfStream) 80 | { 81 | string line = reader.ReadLine(); 82 | 83 | if (string.IsNullOrEmpty(line)) 84 | { 85 | continue; 86 | } 87 | 88 | line = line.Trim(); 89 | 90 | if (line.StartsWith("#")) 91 | { 92 | continue; 93 | } 94 | 95 | if (line.StartsWith("[")) 96 | { 97 | symmetric = line.Contains("symmetric"); 98 | 99 | continue; 100 | } 101 | 102 | var path = Path.GetFullPath(Path.Combine(directory, line)); 103 | 104 | if (!File.Exists(path)) 105 | { 106 | Console.WriteLine("File not found: {0}", path); 107 | continue; 108 | } 109 | 110 | if (symmetric) 111 | { 112 | symmetricList.Add(new MatrixFile() { Path = path, Symmetric = symmetric }); 113 | } 114 | else 115 | { 116 | generalList.Add(new MatrixFile() { Path = path, Symmetric = symmetric }); 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /CSparse.Benchmark/CSparse.Benchmark.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Exe 6 | net8.0 7 | benchmark 8 | CSparse 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /CSparse.Benchmark/Double/BenchmarkRunner.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double 3 | { 4 | using CSparse.Benchmark; 5 | using CSparse.Double.Benchmarks; 6 | using System; 7 | using System.IO; 8 | 9 | public class BenchmarkRunner 10 | { 11 | public static void Run(string dataDirectory, string benchmarkFile, bool preload = true) 12 | { 13 | if (!File.Exists(benchmarkFile)) 14 | { 15 | Console.WriteLine("File not found: '{0}'", benchmarkFile); 16 | return; 17 | } 18 | 19 | if (!Directory.Exists(dataDirectory)) 20 | { 21 | Console.WriteLine("Directory not found: '{0}'", dataDirectory); 22 | return; 23 | } 24 | 25 | var collection = new MatrixFileCollection(benchmarkFile, dataDirectory); 26 | 27 | // Preloading will speed up the benchmark, but consume more memory. 28 | if (preload) 29 | { 30 | Console.WriteLine("Loading matrix collection ..."); 31 | collection.Preload(); 32 | } 33 | 34 | Console.WriteLine("Starting UMFPACK benchmark ..."); 35 | RunUmfpack(collection); 36 | 37 | Console.WriteLine("Starting CHOLMOD benchmark ..."); 38 | RunCholmod(collection); 39 | 40 | Console.WriteLine("Starting SuperLU benchmark ..."); 41 | RunSuperLU(collection); 42 | 43 | Console.WriteLine("Starting PARDISO benchmark ..."); 44 | RunPardiso(collection); 45 | } 46 | 47 | private static void RunUmfpack(MatrixFileCollection collection) 48 | { 49 | var benchmark = new BenchmarkUmfpack(collection); 50 | 51 | var export = new JsonExport("UMFPACK", DateTime.UtcNow.ToString("s")); 52 | 53 | benchmark.Run(export); 54 | 55 | export.Save("benchmark-umfpack.json"); 56 | } 57 | 58 | private static void RunCholmod(MatrixFileCollection collection) 59 | { 60 | var benchmark = new BenchmarkCholmod(collection); 61 | 62 | var export = new JsonExport("CHOLMOD", DateTime.UtcNow.ToString("s")); 63 | 64 | benchmark.Run(export); 65 | 66 | export.Save("benchmark-cholmod.json"); 67 | } 68 | 69 | private static void RunSuperLU(MatrixFileCollection collection) 70 | { 71 | var benchmark = new BenchmarkSuperLU(collection); 72 | 73 | var export = new JsonExport("SuperLU", DateTime.UtcNow.ToString("s")); 74 | 75 | benchmark.Run(export); 76 | 77 | export.Save("benchmark-superlu.json"); 78 | } 79 | 80 | private static void RunPardiso(MatrixFileCollection collection) 81 | { 82 | var benchmark = new BenchmarkPardiso(collection); 83 | 84 | var export = new JsonExport("PARDISO", DateTime.UtcNow.ToString("s")); 85 | 86 | benchmark.Run(export); 87 | 88 | export.Save("benchmark-pardiso.json"); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /CSparse.Benchmark/Double/Benchmarks/BenchmarkCholmod.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Benchmarks 3 | { 4 | using CSparse.Benchmark; 5 | using CSparse.Double.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | using CSparse.Storage; 8 | using System; 9 | 10 | class BenchmarkCholmod : Benchmark 11 | { 12 | public BenchmarkCholmod(MatrixFileCollection collection) 13 | : base(collection) 14 | { 15 | } 16 | 17 | protected override IDisposableSolver CreateSolver(CompressedColumnStorage matrix, bool symmetric) 18 | { 19 | var solver = new Cholmod((SparseMatrix)matrix); 20 | 21 | if (!symmetric) 22 | { 23 | throw new Exception("CHOLMOD expects symmetric matrix."); 24 | } 25 | 26 | return solver; 27 | } 28 | 29 | protected override double[] CreateTestVector(int size) 30 | { 31 | return Vector.Create(size, 1.0); 32 | } 33 | 34 | protected override double ComputeError(int n, double[] actual, double[] expected) 35 | { 36 | return Helper.ComputeError(n, actual, expected); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /CSparse.Benchmark/Double/Benchmarks/BenchmarkPardiso.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Benchmarks 3 | { 4 | using CSparse.Benchmark; 5 | using CSparse.Double.Factorization.MKL; 6 | using CSparse.Factorization; 7 | using CSparse.Interop.MKL.Pardiso; 8 | using CSparse.Storage; 9 | 10 | class BenchmarkPardiso : Benchmark 11 | { 12 | public BenchmarkPardiso(MatrixFileCollection collection) 13 | : base(collection) 14 | { 15 | } 16 | 17 | protected override IDisposableSolver CreateSolver(CompressedColumnStorage matrix, bool symmetric) 18 | { 19 | int mtype = symmetric ? PardisoMatrixType.RealStructurallySymmetric : PardisoMatrixType.RealNonsymmetric; 20 | 21 | var solver = new Pardiso((SparseMatrix)matrix, mtype); 22 | 23 | var options = solver.Options; 24 | 25 | // Fill-in reordering from METIS. 26 | options.ColumnOrderingMethod = PardisoOrdering.NestedDissection; 27 | 28 | // Max numbers of iterative refinement steps. 29 | options.IterativeRefinement = 2; 30 | 31 | // Perturb the pivot elements with 1E-13. 32 | options.PivotingPerturbation = 13; 33 | 34 | // Use non-symmetric permutation and scaling MPS. 35 | options.Scaling = true; 36 | 37 | // Maximum weighted matching algorithm is switched-on (default for non-symmetric). 38 | options.WeightedMatching = true; 39 | 40 | if (symmetric) 41 | { 42 | // Maximum weighted matching algorithm is switched-off (default for symmetric). 43 | // Try to enable in case of inappropriate accuracy. 44 | options.WeightedMatching = false; 45 | } 46 | 47 | options.ZeroBasedIndexing = true; 48 | options.CheckMatrix = true; 49 | 50 | return solver; 51 | } 52 | 53 | protected override double[] CreateTestVector(int size) 54 | { 55 | return Vector.Create(size, 1.0); 56 | } 57 | 58 | protected override double ComputeError(int n, double[] actual, double[] expected) 59 | { 60 | return Helper.ComputeError(n, actual, expected); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /CSparse.Benchmark/Double/Benchmarks/BenchmarkSuperLU.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Benchmarks 3 | { 4 | using CSparse.Benchmark; 5 | using CSparse.Double.Factorization; 6 | using CSparse.Factorization; 7 | using CSparse.Interop.SuperLU; 8 | using CSparse.Storage; 9 | 10 | class BenchmarkSuperLU : Benchmark 11 | { 12 | public BenchmarkSuperLU(MatrixFileCollection collection) 13 | : base(collection) 14 | { 15 | } 16 | 17 | protected override IDisposableSolver CreateSolver(CompressedColumnStorage matrix, bool symmetric) 18 | { 19 | var solver = new SuperLU((SparseMatrix)matrix); 20 | 21 | if (symmetric) 22 | { 23 | var options = solver.Options; 24 | 25 | options.SymmetricMode = true; 26 | options.ColumnOrderingMethod = OrderingMethod.MinimumDegreeAtPlusA; 27 | options.DiagonalPivotThreshold = 0.001; 28 | } 29 | 30 | return solver; 31 | } 32 | 33 | protected override double[] CreateTestVector(int size) 34 | { 35 | return Vector.Create(size, 1.0); 36 | } 37 | 38 | protected override double ComputeError(int n, double[] actual, double[] expected) 39 | { 40 | return Helper.ComputeError(n, actual, expected); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /CSparse.Benchmark/Double/Benchmarks/BenchmarkUmfpack.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Benchmarks 3 | { 4 | using CSparse.Benchmark; 5 | using CSparse.Double.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | using CSparse.Interop.SuiteSparse.Umfpack; 8 | using CSparse.Storage; 9 | 10 | class BenchmarkUmfpack : Benchmark 11 | { 12 | public BenchmarkUmfpack(MatrixFileCollection collection) 13 | : base(collection) 14 | { 15 | } 16 | 17 | protected override IDisposableSolver CreateSolver(CompressedColumnStorage matrix, bool symmetric) 18 | { 19 | var solver = new Umfpack((SparseMatrix)matrix); 20 | 21 | if (symmetric) 22 | { 23 | solver.Control.Strategy = UmfpackStrategy.Symmetric; 24 | } 25 | 26 | return solver; 27 | } 28 | 29 | protected override double[] CreateTestVector(int size) 30 | { 31 | return Vector.Create(size, 1.0); 32 | } 33 | 34 | protected override double ComputeError(int n, double[] actual, double[] expected) 35 | { 36 | return Helper.ComputeError(n, actual, expected); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /CSparse.Benchmark/Double/Helper.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double 3 | { 4 | static class Helper 5 | { 6 | public static double ComputeError(int n, double[] actual, double[] expected, bool relativeError = true) 7 | { 8 | var e = Vector.Clone(actual); 9 | 10 | Vector.Axpy(-1.0, expected, e); 11 | 12 | if (relativeError) 13 | { 14 | return Vector.Norm(n, e) / Vector.Norm(n, expected); 15 | } 16 | 17 | return Vector.Norm(n, e); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /CSparse.Benchmark/Double/SparseMatrixExtensions.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double 3 | { 4 | using CSparse.Storage; 5 | using System.Numerics; 6 | 7 | static class SparseMatrixExtensions 8 | { 9 | /// 10 | /// Multiplies a real-valued (m-by-n) matrix by a complex vector, y = A*x. 11 | /// 12 | /// Vector of length n (column count). 13 | /// Vector of length m (row count), containing the result. 14 | public static void Multiply(this CompressedColumnStorage A, Complex[] x, Complex[] y) 15 | { 16 | var ax = A.Values; 17 | var ap = A.ColumnPointers; 18 | var ai = A.RowIndices; 19 | 20 | int rowCount = A.RowCount; 21 | int columnCount = A.ColumnCount; 22 | 23 | for (int j = 0; j < rowCount; j++) 24 | { 25 | y[j] = Complex.Zero; 26 | } 27 | 28 | int end; 29 | Complex xi; 30 | 31 | for (int i = 0; i < columnCount; i++) 32 | { 33 | xi = x[i]; 34 | 35 | end = ap[i + 1]; 36 | 37 | for (int k = ap[i]; k < end; k++) 38 | { 39 | y[ai[k]] += ax[k] * xi; 40 | } 41 | } 42 | } 43 | 44 | /// 45 | /// Multiplies a real-valued (m-by-n) matrix by a complex vector, y = alpha * A * x + beta * y. 46 | /// 47 | /// Scaling factor for vector x. 48 | /// Vector of length n (column count). 49 | /// Scaling factor for vector y. 50 | /// Vector of length m (row count), containing the result. 51 | public static void Multiply(this CompressedColumnStorage A, Complex alpha, Complex[] x, Complex beta, Complex[] y) 52 | { 53 | var ax = A.Values; 54 | var ap = A.ColumnPointers; 55 | var ai = A.RowIndices; 56 | 57 | int rowCount = A.RowCount; 58 | int columnCount = A.ColumnCount; 59 | 60 | // Scale y by beta 61 | for (int j = 0; j < rowCount; j++) 62 | { 63 | y[j] = beta * y[j]; 64 | } 65 | 66 | int end; 67 | Complex xi; 68 | 69 | for (int i = 0; i < columnCount; i++) 70 | { 71 | xi = alpha * x[i]; 72 | 73 | end = ap[i + 1]; 74 | 75 | for (int k = ap[i]; k < end; k++) 76 | { 77 | y[ai[k]] += ax[k] * xi; 78 | } 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /CSparse.Benchmark/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | namespace ConsoleApp 6 | { 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | if (args.Length == 0 || args[0] == "--arpack") 12 | { 13 | CSparse.Examples.Double.TestArpack.Run(); 14 | CSparse.Examples.Complex.TestArpack.Run(); 15 | CSparse.Examples.Double.TestSpectra.Run(); 16 | } 17 | else 18 | { 19 | var c = ParseCommandlineArgs(args); 20 | 21 | CSparse.Double.BenchmarkRunner.Run(c["data"], c["benchmark"]); 22 | } 23 | 24 | Console.WriteLine("Done."); 25 | } 26 | 27 | private static Dictionary ParseCommandlineArgs(string[] args) 28 | { 29 | var c = new Dictionary(); 30 | 31 | // The data directory. 32 | c["data"] = Path.GetFullPath("./data"); 33 | 34 | // The benchmark file. 35 | c["benchmark"] = "benchmark.lst"; 36 | 37 | int length = args.Length; 38 | 39 | for (int i = 0; i < length; i++) 40 | { 41 | var arg = args[i]; 42 | 43 | if ((arg == "-d" || arg == "--data-dir") && i + 1 < length) 44 | { 45 | c["data"] = Path.GetFullPath(args[i + 1]); 46 | i++; 47 | } 48 | else if ((arg == "-b" || arg == "--benchmark-file") && i + 1 < length) 49 | { 50 | c["benchmark"] = args[i + 1]; 51 | i++; 52 | } 53 | } 54 | 55 | return c; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /CSparse.Benchmark/StorageExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse 2 | { 3 | using CSparse.Storage; 4 | using System; 5 | 6 | /// 7 | /// CompressedColumnStorage extension methods. 8 | /// 9 | public static class CompressedColumnStorageExtensions 10 | { 11 | /// 12 | /// Test if any matrix entry satisfies the given predicate. 13 | /// 14 | /// 15 | /// The matrix. 16 | /// The predicate. 17 | /// 18 | public static bool Any(this CompressedColumnStorage matrix, Func predicate) 19 | where T : struct, IEquatable, IFormattable 20 | { 21 | int columns = matrix.ColumnCount; 22 | 23 | var ax = matrix.Values; 24 | var ap = matrix.ColumnPointers; 25 | var ai = matrix.RowIndices; 26 | 27 | for (int i = 0; i < columns; i++) 28 | { 29 | int end = ap[i + 1]; 30 | for (int j = ap[i]; j < end; j++) 31 | { 32 | if (predicate(ai[j], i, ax[j])) 33 | { 34 | return true; 35 | } 36 | } 37 | } 38 | 39 | return false; 40 | } 41 | 42 | /// 43 | /// Test whether the matrix is upper triangular. 44 | /// 45 | /// 46 | /// The matrix. 47 | /// If true, no diagonal entries are allowed. 48 | /// 49 | public static bool IsUpper(this CompressedColumnStorage matrix, bool strict = false) 50 | where T : struct, IEquatable, IFormattable 51 | { 52 | return strict ? !Any(matrix, (i, j, a) => i >= j) : !Any(matrix, (i, j, a) => i > j); 53 | } 54 | 55 | /// 56 | /// Test whether the matrix is lower triangular. 57 | /// 58 | /// 59 | /// The matrix. 60 | /// If true, no diagonal entries are allowed. 61 | /// 62 | public static bool IsLower(this CompressedColumnStorage matrix, bool strict = false) 63 | where T : struct, IEquatable, IFormattable 64 | { 65 | return strict ? !Any(matrix, (i, j, a) => i <= j) : !Any(matrix, (i, j, a) => i < j); 66 | } 67 | 68 | /// 69 | /// Expand matrix to full storage (symmetric matrix stores upper part only). 70 | /// 71 | public static CompressedColumnStorage Expand(this CompressedColumnStorage A) 72 | where T : struct, IEquatable, IFormattable 73 | { 74 | if (A.IsUpper() || A.IsLower()) 75 | { 76 | // Transpose A. 77 | var B = A.Transpose(); 78 | 79 | // Remove diagonal. 80 | B.Keep((i, j, a) => i != j); 81 | 82 | return A.Add(B); 83 | } 84 | 85 | return A; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /CSparse.Benchmark/benchmark.lst: -------------------------------------------------------------------------------- 1 | # Matrix collection from https://www.advanpix.com/2013/09/05/direct-solvers-for-sparse-matrices/ 2 | 3 | [symmetric] 4 | 5 | nos1.mtx 6 | nos2.mtx 7 | nos3.mtx 8 | nos4.mtx 9 | nos5.mtx 10 | nos6.mtx 11 | nos7.mtx 12 | gr_30_30.mtx 13 | bcsstk27.mtx 14 | bcsstk01.mtx 15 | bcsstk02.mtx 16 | bcsstk03.mtx 17 | bcsstk04.mtx 18 | bcsstk05.mtx 19 | bcsstk06.mtx 20 | bcsstk07.mtx 21 | bcsstk08.mtx 22 | bcsstk09.mtx 23 | bcsstk10.mtx 24 | bcsstk11.mtx 25 | bcsstk12.mtx 26 | bcsstk13.mtx 27 | bcsstk14.mtx 28 | bcsstk15.mtx 29 | bcsstk16.mtx 30 | bcsstk17.mtx 31 | bcsstk18.mtx 32 | s1rmq4m1.mtx 33 | s2rmq4m1.mtx 34 | s3rmq4m1.mtx 35 | s1rmt3m1.mtx 36 | s2rmt3m1.mtx 37 | s3rmt3m1.mtx 38 | s3rmt3m3.mtx 39 | 40 | [general] 41 | 42 | west0067.mtx 43 | west0132.mtx 44 | west0156.mtx 45 | west0167.mtx 46 | west0381.mtx 47 | west0479.mtx 48 | west0497.mtx 49 | west0655.mtx 50 | west0989.mtx 51 | west1505.mtx 52 | west2021.mtx 53 | bp___200.mtx 54 | bp___400.mtx 55 | bp___600.mtx 56 | bp___800.mtx 57 | bp__1000.mtx 58 | bp__1200.mtx 59 | bp__1400.mtx 60 | bp__1600.mtx 61 | impcol_a.mtx 62 | impcol_b.mtx 63 | impcol_c.mtx 64 | impcol_d.mtx 65 | impcol_e.mtx 66 | mcca.mtx 67 | mcfe.mtx 68 | nnc261.mtx 69 | nnc666.mtx 70 | nnc1374.mtx 71 | orsirr_2.mtx 72 | orsirr_1.mtx 73 | orsreg_1.mtx 74 | watt__1.mtx 75 | watt__1.mtx 76 | lns_3937.mtx 77 | lnsp3937.mtx 78 | sherman1.mtx 79 | sherman2.mtx 80 | sherman3.mtx 81 | sherman4.mtx 82 | sherman5.mtx 83 | e05r0500.mtx 84 | e20r0500.mtx -------------------------------------------------------------------------------- /CSparse.Interop.Tests/AMD/TestCOLAMD.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.Tests.AMD 2 | { 3 | using CSparse.Interop.SuiteSparse.Ordering; 4 | 5 | class TestCOLAMD 6 | { 7 | public bool TestCOLAMD1() 8 | { 9 | GetData_COLAMD(out int a_rows, out int a_cols, out int[] ap, out int[] ai, out int b_n, out int[] bp, out int[] bi); 10 | 11 | var colamd = new COLAMD(); 12 | 13 | var info = colamd.Order(a_rows, a_cols, ai, ap); 14 | 15 | var p = ap; 16 | 17 | return info.Status >= 0 && Permutation.IsValid(p, a_cols); 18 | 19 | /* 20 | var symamd = new SYMAMD(); 21 | 22 | p = new int[b_n + 1]; 23 | 24 | info = symamd.Order(b_n, bi, bp, p); 25 | 26 | return info.Status >= 0 && Permutation.IsValid(p); 27 | //*/ 28 | } 29 | 30 | public bool TestCCOLAMD1() 31 | { 32 | GetData_COLAMD(out int a_rows, out int a_cols, out int[] ap, out int[] ai, out int b_n, out int[] bp, out int[] bi); 33 | 34 | var colamd = new COLAMD(); 35 | 36 | var info = colamd.Order(a_rows, a_cols, ai, ap, null); 37 | 38 | var p = ap; 39 | 40 | return info.Status >= 0 && Permutation.IsValid(p, a_cols); 41 | } 42 | 43 | #region Test data 44 | 45 | public static void GetData_COLAMD(out int a_rows, out int a_cols, out int[] ap, out int[] ai, out int b_n, out int[] bp, out int[] bi) 46 | { 47 | a_rows = 5; 48 | a_cols = 4; 49 | 50 | ap = new int[] { 0, 3, 5, 9, 11 }; 51 | ai = new int[] { 52 | /* col 0 */ 0, 1, 4, 53 | /* col 1 */ 2, 4, 54 | /* col 2 */ 0, 1, 2, 3, 55 | /* col 3 */ 1, 3 56 | }; 57 | 58 | b_n = 5; 59 | 60 | bp = new int[] { 0, 1, 3, 3, 4, 4 }; 61 | bi = new int[] { 62 | /* col 0 */ 1, 63 | /* col 1 */ 2, 3, 64 | /* col 2 */ 65 | /* col 3 */ 4 66 | }; 67 | 68 | // Note: only strictly lower triangular part is included, since symamd 69 | // ignores the diagonal and upper triangular part of B. 70 | } 71 | 72 | #endregion 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/AMD/TestRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CSparse.Interop.Tests.AMD 4 | { 5 | internal class TestRunner 6 | { 7 | public static void Run() 8 | { 9 | var amd = new TestAMD(); 10 | RunSafe("AMD", () => amd.TestAMD1() && amd.TestAMD2()); 11 | RunSafe("CAMD", () => amd.TestCAMD1() && amd.TestCAMD2()); 12 | 13 | var colamd = new TestCOLAMD(); 14 | RunSafe("COLAMD", colamd.TestCOLAMD1); 15 | RunSafe("CCOLAMD", colamd.TestCCOLAMD1); 16 | 17 | Console.WriteLine(); 18 | } 19 | 20 | private static void RunSafe(string name, Func action) 21 | { 22 | try 23 | { 24 | Console.Write("Running {0} tests ... ", name); 25 | 26 | if (action()) 27 | { 28 | Display.Ok("OK"); 29 | } 30 | else 31 | { 32 | Display.Error("failed"); 33 | } 34 | } 35 | catch (Exception e) 36 | { 37 | Display.Error(e.Message); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/CSparse.Interop.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/EigenSolvers/TestArpack.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.Tests.Complex.EigenSolvers 2 | { 3 | using CSparse.Complex; 4 | using CSparse.Complex.Solver; 5 | using System; 6 | using System.Diagnostics; 7 | 8 | class TestArpack 9 | { 10 | private const double ERROR_THRESHOLD = 1e-3; 11 | 12 | public void Run(int size) 13 | { 14 | Console.Write("Testing ARPACK ... "); 15 | 16 | // Number of eigenvalues to compute. 17 | int k = 5; 18 | 19 | // Exact eigenvalues. 20 | var z = new double[k]; 21 | 22 | size = (int)Math.Sqrt(size) + 1; 23 | 24 | var A = (SparseMatrix)Generate.Laplacian(size, size, z); 25 | 26 | try 27 | { 28 | Run(A, k, true); 29 | } 30 | catch (Exception e) 31 | { 32 | Display.Error(e.Message); 33 | } 34 | } 35 | 36 | public void Run(SparseMatrix A, int m, bool symmetric) 37 | { 38 | var solver = new Arpack(A, symmetric) 39 | { 40 | Tolerance = 1e-6, 41 | ComputeEigenVectors = true 42 | }; 43 | 44 | var timer = Stopwatch.StartNew(); 45 | 46 | var result = solver.SolveStandard(m, 0.0); 47 | //var result = solver.SolveStandard(m, Spectrum.SmallestMagnitude); 48 | 49 | //var result = solver.SolveStandard(m, 8.0); 50 | //var result = solver.SolveStandard(m, Spectrum.LargestMagnitude); 51 | 52 | timer.Stop(); 53 | 54 | Display.Time(timer.Elapsed); 55 | 56 | result.EnsureSuccess(); 57 | 58 | if (Helper.CheckResiduals(A, result)) 59 | { 60 | Display.Ok("OK"); 61 | } 62 | else 63 | { 64 | Display.Warning("residual error too large"); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/Helper.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Solvers; 6 | using CSparse.Storage; 7 | using System; 8 | using Complex = System.Numerics.Complex; 9 | 10 | static class Helper 11 | { 12 | private const double ERROR_THRESHOLD = 1e-3; 13 | 14 | #region Linear equations 15 | 16 | public static double ComputeError(Complex[] actual, Complex[] expected, bool relativeError = true) 17 | { 18 | var e = Vector.Clone(actual); 19 | 20 | Vector.Axpy(-1.0, expected, e); 21 | 22 | int n = e.Length; 23 | 24 | if (relativeError) 25 | { 26 | return Vector.Norm(n, e) / Vector.Norm(n, expected); 27 | } 28 | 29 | return Vector.Norm(n, e); 30 | } 31 | 32 | public static double ComputeResidual(CompressedColumnStorage A, Complex[] x, Complex[] b, bool relativeError = true) 33 | { 34 | var e = Vector.Clone(b); 35 | 36 | A.Multiply(-1.0, x, 1.0, e); 37 | 38 | int n = A.RowCount; 39 | 40 | if (relativeError) 41 | { 42 | return Vector.Norm(n, e) / (A.FrobeniusNorm() * Vector.Norm(n, b)); 43 | } 44 | 45 | return Vector.Norm(n, e); 46 | } 47 | 48 | #endregion 49 | 50 | #region Eigenvalues 51 | 52 | /// 53 | /// Check residuals of eigenvalue problem. 54 | /// 55 | /// The matrix. 56 | /// The eigensolver result. 57 | /// True, if all residuals are below threshold. 58 | public static bool CheckResiduals(SparseMatrix A, IEigenSolverResult result) 59 | { 60 | int n = A.RowCount; 61 | 62 | var m = result.ConvergedEigenValues; 63 | 64 | var v = result.EigenValues; 65 | var X = result.EigenVectors; 66 | 67 | var x = new Complex[n]; 68 | var y = new Complex[n]; 69 | 70 | for (int i = 0; i < m; i++) 71 | { 72 | var lambda = v[i].Real; 73 | 74 | X.Column(i, x); 75 | 76 | Vector.Copy(x, y); 77 | 78 | // y = A*x - lambda*x 79 | A.Multiply(1.0, x, -lambda, y); 80 | 81 | double r = Vector.Norm(n, y); 82 | 83 | if (r > ERROR_THRESHOLD) 84 | { 85 | return false; 86 | } 87 | } 88 | 89 | return true; 90 | } 91 | 92 | #endregion 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestCXSparseCholesky.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | using System.Numerics; 8 | 9 | class TestCXSparseCholesky : TestBase 10 | { 11 | public TestCXSparseCholesky() 12 | : base("CXSparse Cholesky") 13 | { 14 | } 15 | 16 | protected override void TestRandom(SparseMatrix matrix) 17 | { 18 | } 19 | 20 | protected override void TestRandomMulti(SparseMatrix matrix) 21 | { 22 | } 23 | 24 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 25 | { 26 | var solver = new CXSparseCholesky(matrix, ColumnOrdering.MinimumDegreeAtPlusA); 27 | 28 | if (!symmetric) 29 | { 30 | // throw 31 | } 32 | 33 | return solver; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestCXSparseLU.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | using System.Numerics; 8 | 9 | class TestCXSparseLU : TestBase 10 | { 11 | public TestCXSparseLU() 12 | : base("CXSparse LU") 13 | { 14 | } 15 | 16 | protected override void TestRandomMulti(SparseMatrix matrix) 17 | { 18 | } 19 | 20 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 21 | { 22 | var solver = new CXSparseLU(matrix, ColumnOrdering.MinimumDegreeAtPlusA, 0.1); 23 | 24 | if (!symmetric) 25 | { 26 | // throw 27 | } 28 | 29 | return solver; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestCXSparseQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | using System.Numerics; 8 | 9 | class TestCXSparseQR : TestBase 10 | { 11 | public TestCXSparseQR() 12 | : base("CXSparse QR") 13 | { 14 | } 15 | 16 | protected override void TestRandomSymmetric(SparseMatrix matrix) 17 | { 18 | } 19 | 20 | protected override void TestRandomMulti(SparseMatrix matrix) 21 | { 22 | } 23 | 24 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 25 | { 26 | var solver = new CXSparseQR(matrix, ColumnOrdering.MinimumDegreeAtA); 27 | 28 | if (!symmetric) 29 | { 30 | // throw 31 | } 32 | 33 | return solver; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestCholmod.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | using System.Numerics; 8 | 9 | class TestCholmod : TestBase 10 | { 11 | public TestCholmod() 12 | : base("CHOLMOD") 13 | { 14 | } 15 | 16 | protected override void TestRandom(SparseMatrix matrix) 17 | { 18 | } 19 | 20 | protected override void TestRandomMulti(SparseMatrix matrix) 21 | { 22 | } 23 | 24 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 25 | { 26 | var solver = new Cholmod(matrix); 27 | 28 | if (!symmetric) 29 | { 30 | // throw 31 | } 32 | 33 | return solver; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestPardiso.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization.MKL; 6 | using CSparse.Factorization; 7 | using CSparse.Interop.MKL.Pardiso; 8 | using System.Numerics; 9 | 10 | class TestPardiso : TestBase 11 | { 12 | public TestPardiso() 13 | : base("PARDISO") 14 | { 15 | } 16 | 17 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 18 | { 19 | // TODO: why does 'ComplexHermitianPositiveDefinite' not work? 20 | int mtype = symmetric ? PardisoMatrixType.ComplexStructurallySymmetric : PardisoMatrixType.ComplexNonsymmetric; 21 | 22 | var solver = new Pardiso(matrix, mtype); 23 | 24 | var options = solver.Options; 25 | 26 | // Fill-in reordering from METIS. 27 | options.ColumnOrderingMethod = PardisoOrdering.NestedDissection; 28 | 29 | // Max numbers of iterative refinement steps. 30 | options.IterativeRefinement = 2; 31 | 32 | // Perturb the pivot elements with 1E-13. 33 | options.PivotingPerturbation = 13; 34 | 35 | // Use non-symmetric permutation and scaling MPS. 36 | options.Scaling = true; 37 | 38 | // Maximum weighted matching algorithm is switched-on (default for non-symmetric). 39 | options.WeightedMatching = true; 40 | 41 | if (symmetric) 42 | { 43 | // Maximum weighted matching algorithm is switched-off (default for symmetric). 44 | // Try to enable in case of inappropriate accuracy. 45 | options.WeightedMatching = false; 46 | } 47 | 48 | options.ZeroBasedIndexing = true; 49 | options.CheckMatrix = true; 50 | 51 | return solver; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestRunner.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Interop.Tests.Complex.EigenSolvers; 6 | using System; 7 | 8 | public static class TestRunner 9 | { 10 | public static void Run(int size, double density) 11 | { 12 | var A = Generate.Random(size, size, density); 13 | var B = Generate.RandomHermitian(size, density, true); 14 | 15 | Console.WriteLine("Running tests (Complex) ... [N = {0}]", size); 16 | Console.WriteLine(); 17 | 18 | new TestSparseCholesky().Run(A, B); 19 | new TestSparseLU().Run(A, B); 20 | new TestSparseQR().Run(A, B); 21 | 22 | new TestCXSparseCholesky().Run(A, B); 23 | new TestCXSparseLU().Run(A, B); 24 | new TestCXSparseQR().Run(A, B); 25 | 26 | new TestUmfpack().Run(A, B); 27 | new TestCholmod().Run(A, B); 28 | new TestSPQR().Run(A, B); 29 | new TestSuperLU().Run(A, B); 30 | new TestPardiso().Run(A, B); 31 | 32 | Console.WriteLine(); 33 | Console.WriteLine("Running eigensolver tests (Complex) ... [N = {0}]", size); 34 | Console.WriteLine(); 35 | 36 | new TestArpack().Run(size); 37 | new TestFeast().Run(size); 38 | 39 | Console.WriteLine(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestSPQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | using System.Numerics; 8 | 9 | class TestSPQR : TestBase 10 | { 11 | public TestSPQR() 12 | : base("SPQR") 13 | { 14 | } 15 | 16 | protected override void TestRandomSymmetric(SparseMatrix matrix) 17 | { 18 | } 19 | 20 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 21 | { 22 | var solver = new SPQR(matrix); 23 | 24 | if (symmetric) 25 | { 26 | } 27 | 28 | return solver; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestSparseCholesky.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization; 6 | using CSparse.Factorization; 7 | using System; 8 | using System.Numerics; 9 | 10 | class TestSparseCholesky : TestBase 11 | { 12 | public TestSparseCholesky() 13 | : base("CSparse.NET Cholesky") 14 | { 15 | } 16 | 17 | protected override void TestRandom(SparseMatrix matrix) 18 | { 19 | } 20 | 21 | protected override void TestRandomMulti(SparseMatrix matrix) 22 | { 23 | } 24 | 25 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 26 | { 27 | if (!symmetric) 28 | { 29 | // throw 30 | } 31 | 32 | return new DisposableSparseCholesky(matrix); 33 | } 34 | } 35 | 36 | class DisposableSparseCholesky : IDisposableSolver 37 | { 38 | SparseCholesky cholesky; 39 | 40 | public int NonZerosCount => cholesky.NonZerosCount; 41 | 42 | public DisposableSparseCholesky(SparseMatrix matrix) 43 | { 44 | cholesky = SparseCholesky.Create(matrix, ColumnOrdering.MinimumDegreeAtPlusA); 45 | } 46 | 47 | public void Solve(Complex[] input, Complex[] result) 48 | { 49 | cholesky.Solve(input, result); 50 | } 51 | 52 | public void Solve(ReadOnlySpan input, Span result) 53 | { 54 | cholesky.Solve(input, result); 55 | } 56 | 57 | public void Dispose() 58 | { 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestSparseLU.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization; 6 | using CSparse.Factorization; 7 | using System; 8 | using System.Numerics; 9 | 10 | class TestSparseLU : TestBase 11 | { 12 | public TestSparseLU() 13 | : base("CSparse.NET LU") 14 | { 15 | } 16 | 17 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 18 | { 19 | return new DisposableSparseLU(matrix); 20 | } 21 | } 22 | 23 | class DisposableSparseLU : IDisposableSolver 24 | { 25 | SparseLU lu; 26 | 27 | public int NonZerosCount => lu.NonZerosCount; 28 | 29 | public DisposableSparseLU(SparseMatrix matrix) 30 | { 31 | lu = SparseLU.Create(matrix, ColumnOrdering.MinimumDegreeAtPlusA, 0.1); 32 | } 33 | 34 | public void Solve(Complex[] input, Complex[] result) 35 | { 36 | lu.Solve(input, result); 37 | } 38 | 39 | public void Solve(ReadOnlySpan input, Span result) 40 | { 41 | lu.Solve(input, result); 42 | } 43 | 44 | public void Dispose() 45 | { 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestSparseQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization; 6 | using CSparse.Factorization; 7 | using System; 8 | using System.Numerics; 9 | 10 | class TestSparseQR : TestBase 11 | { 12 | public TestSparseQR() 13 | : base("CSparse.NET QR") 14 | { 15 | } 16 | 17 | protected override void TestRandomSymmetric(SparseMatrix matrix) 18 | { 19 | } 20 | 21 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 22 | { 23 | return new DisposableSparseQR(matrix); 24 | } 25 | } 26 | 27 | class DisposableSparseQR : IDisposableSolver 28 | { 29 | SparseQR qr; 30 | 31 | public int NonZerosCount => qr.NonZerosCount; 32 | 33 | public DisposableSparseQR(SparseMatrix matrix) 34 | { 35 | qr = SparseQR.Create(matrix, ColumnOrdering.MinimumDegreeAtA); 36 | } 37 | 38 | public void Solve(Complex[] input, Complex[] result) 39 | { 40 | qr.Solve(input, result); 41 | } 42 | 43 | public void Solve(ReadOnlySpan input, Span result) 44 | { 45 | qr.Solve(input, result); 46 | } 47 | 48 | public void Dispose() 49 | { 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestSuperLU.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization; 6 | using CSparse.Factorization; 7 | using CSparse.Interop.SuperLU; 8 | using System.Numerics; 9 | 10 | class TestSuperLU : TestBase 11 | { 12 | public TestSuperLU() 13 | : base("SuperLU") 14 | { 15 | } 16 | 17 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 18 | { 19 | var solver = new SuperLU(matrix); 20 | 21 | if (symmetric) 22 | { 23 | var options = solver.Options; 24 | 25 | options.SymmetricMode = true; 26 | options.ColumnOrderingMethod = OrderingMethod.MinimumDegreeAtPlusA; 27 | options.DiagonalPivotThreshold = 0.001; 28 | } 29 | 30 | return solver; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Complex/TestUmfpack.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Complex 3 | { 4 | using CSparse.Complex; 5 | using CSparse.Complex.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | using CSparse.Interop.SuiteSparse.Umfpack; 8 | using System.Numerics; 9 | 10 | class TestUmfpack : TestBase 11 | { 12 | public TestUmfpack() 13 | : base("UMFPACK") 14 | { 15 | } 16 | 17 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 18 | { 19 | var solver = new Umfpack(matrix); 20 | 21 | if (symmetric) 22 | { 23 | var options = solver.Control; 24 | 25 | options.Strategy = UmfpackStrategy.Symmetric; 26 | } 27 | 28 | return solver; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Config.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.Tests 2 | { 3 | class Config 4 | { 5 | public static bool Verbose = false; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Display.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests 3 | { 4 | using System; 5 | using System.Globalization; 6 | 7 | static class Display 8 | { 9 | public static void Time(TimeSpan time) 10 | { 11 | Info(string.Format(CultureInfo.InvariantCulture, "[{0:0.000s}] ", time.TotalSeconds), ConsoleColor.DarkGray, false); 12 | } 13 | 14 | public static void Ok(string message) 15 | { 16 | Info(message, ConsoleColor.DarkGreen); 17 | } 18 | 19 | public static void Warning(string message) 20 | { 21 | Info(message, ConsoleColor.DarkYellow); 22 | } 23 | 24 | public static void Error(string message, bool cleanup = true) 25 | { 26 | if (cleanup) 27 | { 28 | message = Cleanup(message); 29 | } 30 | 31 | Info(message, ConsoleColor.DarkRed); 32 | } 33 | 34 | public static void Info(string message, ConsoleColor color, bool newline = true) 35 | { 36 | var colorSave = Console.ForegroundColor; 37 | 38 | Console.ForegroundColor = color; 39 | 40 | if (newline) 41 | { 42 | Console.WriteLine(message); 43 | } 44 | else 45 | { 46 | Console.Write(message); 47 | } 48 | 49 | Console.ForegroundColor = colorSave; 50 | } 51 | 52 | private static string Cleanup(string message) 53 | { 54 | // Try to cleanup lengthy error messages. 55 | if (message.Length > 200) 56 | { 57 | int i = message.IndexOf('.'); 58 | int j = message.IndexOf('.', i + 1); 59 | if (j > 0 && j < i + 50) i = j; 60 | message = (i > 0 && i < 200) ? message.Substring(0, i + 1) : message.Substring(0, 200) + " ..."; 61 | } 62 | 63 | return message; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/EigenSolvers/TestArpack.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.Tests.Double.EigenSolvers 2 | { 3 | using CSparse.Double; 4 | using CSparse.Double.Solver; 5 | using CSparse.Storage; 6 | using System; 7 | using System.Diagnostics; 8 | 9 | class TestArpack 10 | { 11 | public void Run(int size) 12 | { 13 | Console.Write("Testing ARPACK ... "); 14 | 15 | // Number of eigenvalues to compute. 16 | int k = 5; 17 | 18 | // Exact eigenvalues. 19 | var z = new double[k]; 20 | 21 | size = (int)Math.Sqrt(size) + 1; 22 | 23 | var A = (SparseMatrix)Generate.Laplacian(size, size, z); 24 | 25 | try 26 | { 27 | Run(A, k, true); 28 | } 29 | catch (Exception e) 30 | { 31 | Display.Error(e.Message); 32 | } 33 | } 34 | 35 | public void Run(SparseMatrix A, int m, bool symmetric) 36 | { 37 | // For real symmetric problems, ARPACK++ expects the matrix to be upper triangular. 38 | var U = A.ToUpper(); 39 | 40 | var solver = new Arpack(U, symmetric) 41 | { 42 | Tolerance = 1e-6, 43 | ComputeEigenVectors = true 44 | }; 45 | 46 | var timer = Stopwatch.StartNew(); 47 | 48 | var result = solver.SolveStandard(m, 0.0); 49 | //var result = solver.SolveStandard(m, Spectrum.SmallestMagnitude); 50 | 51 | //var result = solver.SolveStandard(m, 8.0); 52 | //var result = solver.SolveStandard(m, Spectrum.LargestMagnitude); 53 | 54 | timer.Stop(); 55 | 56 | Display.Time(timer.Elapsed); 57 | 58 | result.EnsureSuccess(); 59 | 60 | if (Helper.CheckResiduals(A, result, symmetric)) 61 | { 62 | Display.Ok("OK"); 63 | } 64 | else 65 | { 66 | Display.Warning("residual error too large"); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/EigenSolvers/TestExtendedEigensolver.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.Tests.Double.EigenSolvers 2 | { 3 | using CSparse.Double; 4 | using CSparse.Double.Solver; 5 | using CSparse.Interop.MKL.ExtendedEigensolver; 6 | using System; 7 | using System.Diagnostics; 8 | 9 | class TestExtendedEigensolver 10 | { 11 | private const double ERROR_THRESHOLD = 1e-3; 12 | 13 | public void Run(int size) 14 | { 15 | Console.Write("Testing MKL Extended Eigensolver ... "); 16 | 17 | // Initial subspace dimension. 18 | int k0 = 5; 19 | 20 | // Exact eigenvalues. 21 | var z = new double[k0]; 22 | 23 | size = (int)Math.Sqrt(size) + 1; 24 | 25 | var A = (SparseMatrix)Generate.Laplacian(size, size, z); 26 | 27 | try 28 | { 29 | Run(A, k0, true); 30 | } 31 | catch (Exception e) 32 | { 33 | Display.Error(e.Message); 34 | } 35 | } 36 | 37 | public void Run(SparseMatrix A, int m, bool symmetric) 38 | { 39 | var solver = new ExtendedEigensolver(A); 40 | 41 | var timer = Stopwatch.StartNew(); 42 | 43 | var result = (ExtendedEigensolverResult)solver.SolveStandard(m, Job.Largest); 44 | 45 | timer.Stop(); 46 | 47 | Display.Time(timer.Elapsed); 48 | 49 | if (result.Status == Interop.MKL.SparseStatus.Success) 50 | { 51 | if (CheckResiduals(A, result)) 52 | { 53 | Display.Ok("OK"); 54 | } 55 | else 56 | { 57 | Display.Warning("residual error too large"); 58 | } 59 | } 60 | else 61 | { 62 | Display.Warning("status = " + result.Status); 63 | } 64 | } 65 | 66 | private static bool CheckResiduals(SparseMatrix A, ExtendedEigensolverResult result) 67 | { 68 | var evals = result.EigenValuesReal(); 69 | var evecs = result.EigenVectorsReal(); 70 | 71 | return Helper.CheckResiduals(A, result.ConvergedEigenValues, evals, evecs); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/EigenSolvers/TestSpectra.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.Tests.Double.EigenSolvers 2 | { 3 | using CSparse.Double; 4 | using CSparse.Double.Solver; 5 | using System; 6 | using System.Diagnostics; 7 | 8 | class TestSpectra 9 | { 10 | public void Run(int size) 11 | { 12 | Console.Write("Testing Spectra ... "); 13 | 14 | // Number of eigenvalues to compute. 15 | int k = 5; 16 | 17 | // Exact eigenvalues. 18 | var z = new double[k]; 19 | 20 | size = (int)Math.Sqrt(size) + 1; 21 | 22 | var A = (SparseMatrix)Generate.Laplacian(size, size, z); 23 | 24 | try 25 | { 26 | Run(A, k, true); 27 | } 28 | catch (Exception e) 29 | { 30 | Display.Error(e.Message); 31 | } 32 | } 33 | 34 | public void Run(SparseMatrix A, int m, bool symmetric) 35 | { 36 | var solver = new Spectra(A, symmetric) 37 | { 38 | Tolerance = 1e-6, 39 | ComputeEigenVectors = true, 40 | ArnoldiCount = m * 3 41 | }; 42 | 43 | var timer = Stopwatch.StartNew(); 44 | 45 | var result = solver.SolveStandard(m, 0.0); 46 | //var result = solver.SolveStandard(m, Spectrum.SmallestMagnitude); 47 | 48 | //var result = solver.SolveStandard(m, 8.0); 49 | //var result = solver.SolveStandard(m, Spectrum.LargestMagnitude); 50 | 51 | timer.Stop(); 52 | 53 | Display.Time(timer.Elapsed); 54 | 55 | result.EnsureSuccess(); 56 | 57 | if (Helper.CheckResiduals(A, result, symmetric)) 58 | { 59 | Display.Ok("OK"); 60 | } 61 | else 62 | { 63 | Display.Warning("residual error too large"); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/SparseMatrixExtensions.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using System.Numerics; 6 | 7 | internal static class SparseMatrixExtensions 8 | { 9 | /// 10 | /// Multiplies a real-valued (m-by-n) matrix by a complex vector, y = A*x. 11 | /// 12 | /// Vector of length n (column count). 13 | /// Vector of length m (row count), containing the result. 14 | public static void Multiply(this SparseMatrix A, Complex[] x, Complex[] y) 15 | { 16 | var ax = A.Values; 17 | var ap = A.ColumnPointers; 18 | var ai = A.RowIndices; 19 | 20 | int rowCount = A.RowCount; 21 | int columnCount = A.ColumnCount; 22 | 23 | for (int j = 0; j < rowCount; j++) 24 | { 25 | y[j] = Complex.Zero; 26 | } 27 | 28 | int end; 29 | Complex xi; 30 | 31 | for (int i = 0; i < columnCount; i++) 32 | { 33 | xi = x[i]; 34 | 35 | end = ap[i + 1]; 36 | 37 | for (int k = ap[i]; k < end; k++) 38 | { 39 | y[ai[k]] += ax[k] * xi; 40 | } 41 | } 42 | } 43 | 44 | /// 45 | /// Multiplies a real-valued (m-by-n) matrix by a complex vector, y = alpha * A * x + beta * y. 46 | /// 47 | /// Scaling factor for vector x. 48 | /// Vector of length n (column count). 49 | /// Scaling factor for vector y. 50 | /// Vector of length m (row count), containing the result. 51 | public static void Multiply(this SparseMatrix A, Complex alpha, Complex[] x, Complex beta, Complex[] y) 52 | { 53 | var ax = A.Values; 54 | var ap = A.ColumnPointers; 55 | var ai = A.RowIndices; 56 | 57 | int rowCount = A.RowCount; 58 | int columnCount = A.ColumnCount; 59 | 60 | // Scale y by beta 61 | for (int j = 0; j < rowCount; j++) 62 | { 63 | y[j] = beta * y[j]; 64 | } 65 | 66 | int end; 67 | Complex xi; 68 | 69 | for (int i = 0; i < columnCount; i++) 70 | { 71 | xi = alpha * x[i]; 72 | 73 | end = ap[i + 1]; 74 | 75 | for (int k = ap[i]; k < end; k++) 76 | { 77 | y[ai[k]] += ax[k] * xi; 78 | } 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestCXSparseCholesky.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | 8 | class TestCXSparseCholesky : TestBase 9 | { 10 | public TestCXSparseCholesky() 11 | : base("CXSparse Cholesky") 12 | { 13 | } 14 | 15 | protected override void TestRandom(SparseMatrix matrix) 16 | { 17 | } 18 | 19 | protected override void TestRandomMulti(SparseMatrix matrix) 20 | { 21 | } 22 | 23 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 24 | { 25 | var solver = new CXSparseCholesky(matrix, ColumnOrdering.MinimumDegreeAtPlusA); 26 | 27 | if (!symmetric) 28 | { 29 | // throw 30 | } 31 | 32 | return solver; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestCXSparseLU.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | 8 | class TestCXSparseLU : TestBase 9 | { 10 | public TestCXSparseLU() 11 | : base("CXSparse LU") 12 | { 13 | } 14 | 15 | protected override void TestRandomMulti(SparseMatrix matrix) 16 | { 17 | } 18 | 19 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 20 | { 21 | var solver = new CXSparseLU(matrix, ColumnOrdering.MinimumDegreeAtPlusA, 0.1); 22 | 23 | if (!symmetric) 24 | { 25 | // throw 26 | } 27 | 28 | return solver; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestCXSparseQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | 8 | class TestCXSparseQR : TestBase 9 | { 10 | public TestCXSparseQR() 11 | : base("CXSparse QR") 12 | { 13 | } 14 | 15 | protected override void TestRandomSymmetric(SparseMatrix matrix) 16 | { 17 | } 18 | 19 | protected override void TestRandomMulti(SparseMatrix matrix) 20 | { 21 | } 22 | 23 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 24 | { 25 | var solver = new CXSparseQR(matrix, ColumnOrdering.MinimumDegreeAtA); 26 | 27 | if (!symmetric) 28 | { 29 | // throw 30 | } 31 | 32 | return solver; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestCholmod.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | 8 | class TestCholmod : TestBase 9 | { 10 | public TestCholmod() 11 | : base("CHOLMOD") 12 | { 13 | } 14 | 15 | protected override void TestRandom(SparseMatrix matrix) 16 | { 17 | } 18 | 19 | protected override void TestRandomMulti(SparseMatrix matrix) 20 | { 21 | } 22 | 23 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 24 | { 25 | var solver = new Cholmod(matrix); 26 | 27 | if (!symmetric) 28 | { 29 | // throw 30 | } 31 | 32 | return solver; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestPardiso.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization.MKL; 6 | using CSparse.Factorization; 7 | using CSparse.Interop.MKL.Pardiso; 8 | using CSparse.Storage; 9 | 10 | class TestPardiso : TestBase 11 | { 12 | public TestPardiso() 13 | : base("PARDISO") 14 | { 15 | } 16 | 17 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 18 | { 19 | if (symmetric && !matrix.IsLower()) 20 | { 21 | // The PARDISO spd solver expects a triangular matrix. 22 | matrix = (SparseMatrix)matrix.ToLower(); 23 | } 24 | 25 | int mtype = symmetric ? PardisoMatrixType.RealSymmetricPositiveDefinite : PardisoMatrixType.RealNonsymmetric; 26 | 27 | var solver = new Pardiso(matrix, mtype); 28 | 29 | var options = solver.Options; 30 | 31 | // Fill-in reordering from METIS. 32 | options.ColumnOrderingMethod = PardisoOrdering.NestedDissection; 33 | 34 | // Max numbers of iterative refinement steps. 35 | options.IterativeRefinement = 2; 36 | 37 | // Perturb the pivot elements with 1E-13. 38 | options.PivotingPerturbation = 13; 39 | 40 | // Use non-symmetric permutation and scaling MPS. 41 | options.Scaling = true; 42 | 43 | // Maximum weighted matching algorithm is switched-on (default for non-symmetric). 44 | options.WeightedMatching = true; 45 | 46 | if (symmetric) 47 | { 48 | // Maximum weighted matching algorithm is switched-off (default for symmetric). 49 | // Try to enable in case of inappropriate accuracy. 50 | options.WeightedMatching = false; 51 | } 52 | 53 | options.ZeroBasedIndexing = true; 54 | options.CheckMatrix = true; 55 | 56 | return solver; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestRunner.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Interop.Tests.Double.EigenSolvers; 5 | using System; 6 | 7 | public static class TestRunner 8 | { 9 | public static void Run(int size, double density) 10 | { 11 | var A = Generate.Random(size, size, density, Random.Shared); 12 | var B = Generate.RandomSymmetric(size, density, true); 13 | 14 | Console.WriteLine("Running tests (Double) ... [N = {0}]", size); 15 | Console.WriteLine(); 16 | 17 | new TestSparseCholesky().Run(A, B); 18 | new TestSparseLU().Run(A, B); 19 | new TestSparseQR().Run(A, B); 20 | 21 | new TestCXSparseCholesky().Run(A, B); 22 | new TestCXSparseLU().Run(A, B); 23 | new TestCXSparseQR().Run(A, B); 24 | 25 | new TestUmfpack().Run(A, B); 26 | new TestCholmod().Run(A, B); 27 | new TestSPQR().Run(A, B); 28 | new TestSuperLU().Run(A, B); 29 | new TestPardiso().Run(A, B); 30 | new TestSparseQR_MKL().Run(A, B); 31 | 32 | Console.WriteLine(); 33 | Console.WriteLine("Running eigensolver tests (Double) ... [N = {0}]", size); 34 | Console.WriteLine(); 35 | 36 | new TestArpack().Run(size); 37 | new TestSpectra().Run(size); 38 | new TestFeast().Run(size); 39 | new TestExtendedEigensolver().Run(size); 40 | 41 | Console.WriteLine(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestSPQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | 8 | class TestSPQR : TestBase 9 | { 10 | public TestSPQR() 11 | : base("SPQR") 12 | { 13 | } 14 | 15 | protected override void TestRandomSymmetric(SparseMatrix matrix) 16 | { 17 | } 18 | 19 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 20 | { 21 | var solver = new SPQR(matrix); 22 | 23 | if (symmetric) 24 | { 25 | } 26 | 27 | return solver; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestSparseCholesky.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization; 6 | using CSparse.Factorization; 7 | using System; 8 | 9 | class TestSparseCholesky : TestBase 10 | { 11 | public TestSparseCholesky() 12 | : base("CSparse.NET Cholesky") 13 | { 14 | } 15 | 16 | protected override void TestRandom(SparseMatrix matrix) 17 | { 18 | } 19 | 20 | protected override void TestRandomMulti(SparseMatrix matrix) 21 | { 22 | } 23 | 24 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 25 | { 26 | if (!symmetric) 27 | { 28 | // throw 29 | } 30 | 31 | return new DisposableSparseCholesky(matrix); 32 | } 33 | } 34 | 35 | class DisposableSparseCholesky : IDisposableSolver 36 | { 37 | SparseCholesky cholesky; 38 | 39 | public int NonZerosCount => cholesky.NonZerosCount; 40 | 41 | public DisposableSparseCholesky(SparseMatrix matrix) 42 | { 43 | cholesky = SparseCholesky.Create(matrix, ColumnOrdering.MinimumDegreeAtPlusA); 44 | } 45 | 46 | public void Solve(double[] input, double[] result) 47 | { 48 | cholesky.Solve(input, result); 49 | } 50 | 51 | public void Solve(ReadOnlySpan input, Span result) 52 | { 53 | cholesky.Solve(input, result); 54 | } 55 | 56 | public void Dispose() 57 | { 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestSparseLU.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization; 6 | using CSparse.Factorization; 7 | using System; 8 | 9 | class TestSparseLU : TestBase 10 | { 11 | public TestSparseLU() 12 | : base("CSparse.NET LU") 13 | { 14 | } 15 | 16 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 17 | { 18 | return new DisposableSparseLU(matrix); 19 | } 20 | } 21 | 22 | class DisposableSparseLU : IDisposableSolver 23 | { 24 | SparseLU lu; 25 | 26 | public int NonZerosCount => lu.NonZerosCount; 27 | 28 | public DisposableSparseLU(SparseMatrix matrix) 29 | { 30 | lu = SparseLU.Create(matrix, ColumnOrdering.MinimumDegreeAtPlusA, 0.1); 31 | } 32 | 33 | public void Solve(double[] input, double[] result) 34 | { 35 | lu.Solve(input, result); 36 | } 37 | 38 | public void Solve(ReadOnlySpan input, Span result) 39 | { 40 | lu.Solve(input, result); 41 | } 42 | 43 | public void Dispose() 44 | { 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestSparseQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization; 6 | using CSparse.Factorization; 7 | using System; 8 | 9 | class TestSparseQR : TestBase 10 | { 11 | public TestSparseQR() 12 | : base("CSparse.NET QR") 13 | { 14 | } 15 | 16 | protected override void TestRandomSymmetric(SparseMatrix matrix) 17 | { 18 | } 19 | 20 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 21 | { 22 | return new DisposableSparseQR(matrix); 23 | } 24 | } 25 | 26 | class DisposableSparseQR : IDisposableSolver 27 | { 28 | SparseQR qr; 29 | 30 | public int NonZerosCount => qr.NonZerosCount; 31 | 32 | public DisposableSparseQR(SparseMatrix matrix) 33 | { 34 | qr = SparseQR.Create(matrix, ColumnOrdering.MinimumDegreeAtA); 35 | } 36 | 37 | public void Solve(double[] input, double[] result) 38 | { 39 | qr.Solve(input, result); 40 | } 41 | 42 | public void Solve(ReadOnlySpan input, Span result) 43 | { 44 | qr.Solve(input, result); 45 | } 46 | 47 | public void Dispose() 48 | { 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestSparseQR_MKL.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization.MKL; 6 | using CSparse.Factorization; 7 | using CSparse.Storage; 8 | 9 | class TestSparseQR_MKL : TestBase 10 | { 11 | public TestSparseQR_MKL() 12 | : base("SparseQR MKL") 13 | { 14 | } 15 | 16 | protected override void TestRandomSymmetric(SparseMatrix matrix) 17 | { 18 | } 19 | 20 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 21 | { 22 | // MKL sparse QR expects CSR storage, so we have to transpose the matrix. 23 | var solver = new SparseQR(new CompressedRowStorage(matrix)); 24 | 25 | if (symmetric) 26 | { 27 | } 28 | 29 | return solver; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestSuperLU.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization; 6 | using CSparse.Factorization; 7 | using CSparse.Interop.SuperLU; 8 | 9 | class TestSuperLU : TestBase 10 | { 11 | public TestSuperLU() 12 | : base("SuperLU") 13 | { 14 | } 15 | 16 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 17 | { 18 | var solver = new SuperLU(matrix); 19 | 20 | if (symmetric) 21 | { 22 | var options = solver.Options; 23 | 24 | options.SymmetricMode = true; 25 | options.ColumnOrderingMethod = OrderingMethod.MinimumDegreeAtPlusA; 26 | options.DiagonalPivotThreshold = 0.001; 27 | } 28 | 29 | return solver; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Double/TestUmfpack.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Tests.Double 3 | { 4 | using CSparse.Double; 5 | using CSparse.Double.Factorization.SuiteSparse; 6 | using CSparse.Factorization; 7 | using CSparse.Interop.SuiteSparse.Umfpack; 8 | 9 | class TestUmfpack : TestBase 10 | { 11 | public TestUmfpack() 12 | : base("UMFPACK") 13 | { 14 | } 15 | 16 | protected override IDisposableSolver CreateSolver(SparseMatrix matrix, bool symmetric) 17 | { 18 | var solver = new Umfpack(matrix); 19 | 20 | if (symmetric) 21 | { 22 | var options = solver.Control; 23 | 24 | options.Strategy = UmfpackStrategy.Symmetric; 25 | } 26 | 27 | return solver; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CSparse.Interop.Tests/Program.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.Tests 2 | { 3 | using System; 4 | using System.Globalization; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | 8 | internal class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | SetImportResolver(); 13 | 14 | ParseCommandlineArgs(args, out int size, out double density); 15 | 16 | Double.TestRunner.Run(size, density); 17 | Complex.TestRunner.Run(size, density); 18 | AMD.TestRunner.Run(); 19 | 20 | //Double.TestCuda.Run(size, density); 21 | //Complex.TestCuda.Run(size, density); 22 | } 23 | 24 | private static void ParseCommandlineArgs(string[] args, out int size, out double density) 25 | { 26 | // Default matrix size. 27 | size = 1000; 28 | 29 | // Default density (non-zeros = size x size x density). 30 | density = 0.01; 31 | 32 | int length = args.Length; 33 | 34 | for (int i = 0; i < length; i++) 35 | { 36 | var arg = args[i]; 37 | 38 | if (arg.Equals("--size") && i + 1 < length) 39 | { 40 | int.TryParse(args[i + 1], out size); 41 | i++; 42 | } 43 | else if (arg.Equals("--density") && i + 1 < length) 44 | { 45 | double.TryParse(args[i + 1], NumberStyles.Any, NumberFormatInfo.InvariantInfo, out density); 46 | i++; 47 | } 48 | } 49 | 50 | if (size < 0 || size > 10000) 51 | { 52 | Console.WriteLine("Parameter 'size' out of range: reset to default (1000)"); 53 | 54 | size = 1000; 55 | } 56 | 57 | if (density < 1e-6 || density > 0.1) 58 | { 59 | Console.WriteLine("Parameter 'density' out of range: reset to default (0.01)"); 60 | 61 | density = 0.01; 62 | } 63 | } 64 | 65 | // In case Windows library names don't match their Linux counterparts, we can modify 66 | // the names to look for, as done below for MKL. 67 | 68 | private static void SetImportResolver() 69 | { 70 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 71 | { 72 | var assembly = AppDomain.CurrentDomain.Load("CSparse.Interop"); 73 | 74 | NativeLibrary.SetDllImportResolver(assembly, DllImportResolver); 75 | } 76 | } 77 | 78 | private static IntPtr DllImportResolver(string library, Assembly assembly, DllImportSearchPath? searchPath) 79 | { 80 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 81 | { 82 | if (library.Equals("mkl_rt.2")) 83 | { 84 | // Trying to find MKL on Linux (specifically Debian). 85 | return NativeLibrary.Load("libmkl_rt.so", assembly, searchPath); 86 | } 87 | } 88 | 89 | // Otherwise, fall back to default import resolver. 90 | return IntPtr.Zero; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /CSparse.Interop.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34525.116 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSparse.Interop", "CSparse.Interop\CSparse.Interop.csproj", "{5235AD90-5E2C-4467-B497-875A79F57F4E}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSparse.Benchmark", "CSparse.Benchmark\CSparse.Benchmark.csproj", "{8E04219C-BCCE-4649-A795-910640B7D90A}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9FA3DB8C-4871-40C0-84E8-16AF52262291}" 11 | ProjectSection(SolutionItems) = preProject 12 | README.md = README.md 13 | EndProjectSection 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSparse.Interop.Tests", "CSparse.Interop.Tests\CSparse.Interop.Tests.csproj", "{B0A3CDE9-8531-4DA7-BF7C-9B031F8159AE}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Debug|x64 = Debug|x64 21 | Release|Any CPU = Release|Any CPU 22 | Release|x64 = Release|x64 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {5235AD90-5E2C-4467-B497-875A79F57F4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {5235AD90-5E2C-4467-B497-875A79F57F4E}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {5235AD90-5E2C-4467-B497-875A79F57F4E}.Debug|x64.ActiveCfg = Debug|Any CPU 28 | {5235AD90-5E2C-4467-B497-875A79F57F4E}.Debug|x64.Build.0 = Debug|Any CPU 29 | {5235AD90-5E2C-4467-B497-875A79F57F4E}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {5235AD90-5E2C-4467-B497-875A79F57F4E}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {5235AD90-5E2C-4467-B497-875A79F57F4E}.Release|x64.ActiveCfg = Release|Any CPU 32 | {5235AD90-5E2C-4467-B497-875A79F57F4E}.Release|x64.Build.0 = Release|Any CPU 33 | {8E04219C-BCCE-4649-A795-910640B7D90A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {8E04219C-BCCE-4649-A795-910640B7D90A}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {8E04219C-BCCE-4649-A795-910640B7D90A}.Debug|x64.ActiveCfg = Debug|Any CPU 36 | {8E04219C-BCCE-4649-A795-910640B7D90A}.Debug|x64.Build.0 = Debug|Any CPU 37 | {8E04219C-BCCE-4649-A795-910640B7D90A}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {8E04219C-BCCE-4649-A795-910640B7D90A}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {8E04219C-BCCE-4649-A795-910640B7D90A}.Release|x64.ActiveCfg = Release|Any CPU 40 | {8E04219C-BCCE-4649-A795-910640B7D90A}.Release|x64.Build.0 = Release|Any CPU 41 | {B0A3CDE9-8531-4DA7-BF7C-9B031F8159AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {B0A3CDE9-8531-4DA7-BF7C-9B031F8159AE}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {B0A3CDE9-8531-4DA7-BF7C-9B031F8159AE}.Debug|x64.ActiveCfg = Debug|Any CPU 44 | {B0A3CDE9-8531-4DA7-BF7C-9B031F8159AE}.Debug|x64.Build.0 = Debug|Any CPU 45 | {B0A3CDE9-8531-4DA7-BF7C-9B031F8159AE}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {B0A3CDE9-8531-4DA7-BF7C-9B031F8159AE}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {B0A3CDE9-8531-4DA7-BF7C-9B031F8159AE}.Release|x64.ActiveCfg = Release|Any CPU 48 | {B0A3CDE9-8531-4DA7-BF7C-9B031F8159AE}.Release|x64.Build.0 = Release|Any CPU 49 | EndGlobalSection 50 | GlobalSection(SolutionProperties) = preSolution 51 | HideSolutionNode = FALSE 52 | EndGlobalSection 53 | GlobalSection(ExtensibilityGlobals) = postSolution 54 | SolutionGuid = {CEB54D15-59AC-4569-BBA3-4034C2A673D7} 55 | EndGlobalSection 56 | EndGlobal 57 | -------------------------------------------------------------------------------- /CSparse.Interop/CSparse.Interop.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | false 6 | true 7 | CSparse.Interop 8 | Interop extensions for CSparse.NET 9 | Dense LU, Cholesky and QR decomposition of real and complex linear systems. 10 | CSparse.Interop 11 | 12 | Copyright Christian Woltering © 2012-2024 13 | Christian Woltering 14 | 4.2.0.0 15 | 4.2.0.0 16 | math sparse matrix lu cholesky qr decomposition factorization 17 | 4.2.0 18 | CSparse.Interop 19 | CSparse 20 | 21 | 22 | 23 | 1591 24 | 25 | 26 | 27 | $(DefineConstants);X64 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Factorization/CUDA/CudaCholesky.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Factorization.CUDA 3 | { 4 | using CSparse.Interop.CUDA; 5 | using CSparse.Storage; 6 | using System; 7 | using System.Numerics; 8 | 9 | // Based on low level interface example cuSolverSp_LowlevelCholesky 10 | 11 | public class CudaCholesky : CuSolverContext 12 | { 13 | private IntPtr _info; 14 | 15 | private bool disposed = false; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The . 21 | /// The sparse matrix. 22 | public CudaCholesky(CudaStream stream, CompressedColumnStorage A) 23 | : this(stream, A, true) 24 | { 25 | } 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// The . 31 | /// The sparse matrix. 32 | /// A value indicating, whether the storage should be transposed. 33 | public CudaCholesky(CudaStream stream, CompressedColumnStorage A, bool transpose) 34 | : base(stream, A, transpose) 35 | { 36 | } 37 | 38 | ~CudaCholesky() 39 | { 40 | Dispose(false); 41 | } 42 | 43 | protected override SolverStatus Solve(int rows, int columns) 44 | { 45 | return NativeMethods.cusolverSpZcsrcholSolve(_p, rows, d_b, d_x, _info, _buffer); 46 | } 47 | 48 | public override bool Singular(double tol) 49 | { 50 | int singularity = 0; 51 | 52 | // Check if the matrix is singular. 53 | Check(NativeMethods.cusolverSpZcsrcholZeroPivot(_p, _info, tol, ref singularity)); 54 | 55 | return singularity >= 0; 56 | } 57 | 58 | protected override void Factorize(int rows, int columns, int nnz, CuSparseContext A) 59 | { 60 | var ap = A.ColumnPointers; 61 | var ai = A.RowIndices; 62 | var ax = A.Values; 63 | 64 | var desc = A.MatrixDescriptor; 65 | 66 | // Analyze chol(A) to know structure of L. 67 | Check(NativeMethods.cusolverSpXcsrcholAnalysis(_p, rows, nnz, desc, ap, ai, _info)); 68 | 69 | int size_internal = 0, size_chol = 0; 70 | 71 | // Workspace for chol(A). 72 | Check(NativeMethods.cusolverSpZcsrcholBufferInfo(_p, rows, nnz, desc, ax, ap, ai, _info, 73 | ref size_internal, ref size_chol)); 74 | 75 | 76 | Cuda.Malloc(ref _buffer, sizeof(char) * size_chol); 77 | 78 | // Compute A = L*L^T. 79 | Check(NativeMethods.cusolverSpZcsrcholFactor(_p, rows, nnz, desc, ax, ap, ai, _info, _buffer)); 80 | } 81 | 82 | protected override void PrepareFactorize() 83 | { 84 | // Create opaque info structure. 85 | Check(NativeMethods.cusolverSpCreateCsrcholInfo(ref _info)); 86 | } 87 | 88 | protected override void Dispose(bool disposing) 89 | { 90 | if (disposed) return; 91 | 92 | if (_info != IntPtr.Zero) 93 | { 94 | Check(NativeMethods.cusolverSpDestroyCsrcholInfo(_info)); 95 | _info = IntPtr.Zero; 96 | } 97 | 98 | disposed = true; 99 | 100 | base.Dispose(disposing); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Factorization/CUDA/CudaQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Factorization.CUDA 3 | { 4 | using CSparse.Interop.CUDA; 5 | using CSparse.Storage; 6 | using System; 7 | using System.Numerics; 8 | 9 | // Based on low level interface example cuSolverSp_LowlevelQR 10 | 11 | public class CudaQR : CuSolverContext 12 | { 13 | private IntPtr _info; 14 | 15 | private bool disposed = false; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The . 21 | /// The sparse matrix. 22 | public CudaQR(CudaStream stream, CompressedColumnStorage A) 23 | : this(stream, A, true) 24 | { 25 | } 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// The . 31 | /// The sparse matrix. 32 | /// A value indicating, whether the storage should be transposed. 33 | public CudaQR(CudaStream stream, CompressedColumnStorage A, bool transpose) 34 | : base(stream, A, transpose) 35 | { 36 | } 37 | 38 | ~CudaQR() 39 | { 40 | Dispose(false); 41 | } 42 | 43 | protected override SolverStatus Solve(int rows, int columns) 44 | { 45 | return NativeMethods.cusolverSpZcsrqrSolve(_p, rows, columns, d_b, d_x, _info, _buffer); 46 | } 47 | 48 | public override bool Singular(double tol) 49 | { 50 | int singularity = 0; 51 | 52 | // Check if the matrix is singular. 53 | Check(NativeMethods.cusolverSpZcsrqrZeroPivot(_p, _info, tol, ref singularity)); 54 | 55 | return singularity >= 0; 56 | } 57 | 58 | protected override void Factorize(int rows, int columns, int nnz, CuSparseContext A) 59 | { 60 | var ap = A.ColumnPointers; 61 | var ai = A.RowIndices; 62 | var ax = A.Values; 63 | 64 | var desc = A.MatrixDescriptor; 65 | 66 | // Analyze qr(A) to know structure of L. 67 | Check(NativeMethods.cusolverSpXcsrqrAnalysis(_p, rows, columns, nnz, desc, ap, ai, _info)); 68 | 69 | int size_internal = 0, size_qr = 0; 70 | 71 | // Workspace for qr(A). 72 | Check(NativeMethods.cusolverSpZcsrqrBufferInfo(_p, rows, columns, nnz, desc, ax, ap, ai, _info, 73 | ref size_internal, ref size_qr)); 74 | 75 | Cuda.Malloc(ref _buffer, sizeof(char) * size_qr); 76 | 77 | Check(NativeMethods.cusolverSpZcsrqrSetup(_p, rows, columns, nnz, desc, ax, ap, ai, 0.0, _info)); 78 | 79 | // Compute A = Q*R. 80 | Check(NativeMethods.cusolverSpZcsrqrFactor(_p, rows, columns, nnz, IntPtr.Zero, IntPtr.Zero, _info, _buffer)); 81 | } 82 | 83 | protected override void PrepareFactorize() 84 | { 85 | // Create opaque info structure. 86 | Check(NativeMethods.cusolverSpCreateCsrqrInfo(ref _info)); 87 | } 88 | 89 | protected override void Dispose(bool disposing) 90 | { 91 | if (disposed) return; 92 | 93 | if (_info != IntPtr.Zero) 94 | { 95 | Check(NativeMethods.cusolverSpDestroyCsrqrInfo(_info)); 96 | _info = IntPtr.Zero; 97 | } 98 | 99 | disposed = true; 100 | 101 | base.Dispose(disposing); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Factorization/MKL/Pardiso.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Factorization.MKL 3 | { 4 | using CSparse.Interop.MKL.Pardiso; 5 | using CSparse.Storage; 6 | using System; 7 | using System.Numerics; 8 | 9 | /// 10 | /// PARDISO wrapper. 11 | /// 12 | public class Pardiso : PardisoContext 13 | { 14 | /// 15 | /// Initializes a new instance of the Pardiso class. 16 | /// 17 | public Pardiso(CompressedColumnStorage matrix) 18 | : base(matrix, PardisoMatrixType.ComplexNonsymmetric) 19 | { 20 | } 21 | 22 | /// 23 | /// Initializes a new instance of the Pardiso class. 24 | /// 25 | public Pardiso(CompressedColumnStorage matrix, int mtype) 26 | : base(matrix, mtype) 27 | { 28 | switch (mtype) 29 | { 30 | case PardisoMatrixType.ComplexHermitianIndefinite: 31 | case PardisoMatrixType.ComplexHermitianPositiveDefinite: 32 | case PardisoMatrixType.ComplexNonsymmetric: 33 | case PardisoMatrixType.ComplexStructurallySymmetric: 34 | case PardisoMatrixType.ComplexSymmetric: 35 | break; 36 | default: 37 | throw new ArgumentException("Invalid matrix type: expected complex.", "mtype"); 38 | } 39 | } 40 | 41 | /// 42 | protected override void Solve(int sys, Complex[] input, Complex[] result) 43 | { 44 | Solve(sys, new DenseMatrix(matrix.RowCount, 1, input), new DenseMatrix(matrix.ColumnCount, 1, result)); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Factorization/SuiteSparse/CXSparseCholesky.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.Common; 5 | using CSparse.Interop.SuiteSparse.CXSparse; 6 | using CSparse.Storage; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Numerics; 10 | using System.Runtime.InteropServices; 11 | 12 | public class CXSparseCholesky : CXSparseContext 13 | { 14 | /// 15 | /// Initializes a new instance of the SuperLU class. 16 | /// 17 | public CXSparseCholesky(CompressedColumnStorage matrix, ColumnOrdering ordering) 18 | : base(matrix, ordering) 19 | { 20 | } 21 | 22 | public override void Solve(Complex[] input, Complex[] result) 23 | { 24 | if (!factorized && DoFactorize() != 0) 25 | { 26 | throw new Exception(); // TODO: exception 27 | } 28 | 29 | var n = matrix.RowCount; 30 | 31 | var h = new List(); 32 | 33 | var b = InteropHelper.Pin(input, h); 34 | var x = InteropHelper.Pin(result, h); 35 | var t = InteropHelper.Pin(w, h); 36 | 37 | try 38 | { 39 | // x = P*b 40 | if (NativeMethods.cs_ci_ipvec(S.pinv, b, t, n) == 0) return; 41 | 42 | // x = L\x 43 | if (NativeMethods.cs_ci_lsolve(N.L, t) == 0) return; 44 | 45 | // x = L'\x 46 | if (NativeMethods.cs_ci_ltsolve(N.L, t) == 0) return; 47 | 48 | // b = P'*x 49 | if (NativeMethods.cs_ci_pvec(S.pinv, t, x, n) == 0) return; 50 | } 51 | finally 52 | { 53 | InteropHelper.Free(h); 54 | } 55 | } 56 | 57 | protected override int DoFactorize() 58 | { 59 | var h = new List(); 60 | var A = CreateSparse(matrix, h); 61 | 62 | try 63 | { 64 | int order = (int)ordering; 65 | 66 | // ordering and symbolic analysis 67 | var pS = NativeMethods.cs_ci_schol(order, ref A); 68 | 69 | if (pS == IntPtr.Zero) 70 | { 71 | return -1; 72 | } 73 | 74 | S = Marshal.PtrToStructure(pS); 75 | 76 | // numeric Cholesky factorization 77 | var pN = NativeMethods.cs_ci_chol(ref A, ref S); 78 | 79 | if (pN == IntPtr.Zero) 80 | { 81 | return -1; 82 | } 83 | 84 | N = Marshal.PtrToStructure(pN); 85 | } 86 | finally 87 | { 88 | InteropHelper.Free(h); 89 | } 90 | 91 | return 0; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Factorization/SuiteSparse/CXSparseLU.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.Common; 5 | using CSparse.Interop.SuiteSparse.CXSparse; 6 | using CSparse.Storage; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Numerics; 10 | using System.Runtime.InteropServices; 11 | 12 | public class CXSparseLU : CXSparseContext 13 | { 14 | private readonly double tol; 15 | 16 | /// 17 | /// Initializes a new instance of the SuperLU class. 18 | /// 19 | public CXSparseLU(CompressedColumnStorage matrix, ColumnOrdering ordering, double tol) 20 | : base(matrix, ordering) 21 | { 22 | this.tol = tol; 23 | } 24 | 25 | public override void Solve(Complex[] input, Complex[] result) 26 | { 27 | if (!factorized && DoFactorize() != 0) 28 | { 29 | throw new Exception(); // TODO: exception 30 | } 31 | 32 | var n = matrix.RowCount; 33 | 34 | var h = new List(); 35 | 36 | var b = InteropHelper.Pin(input, h); 37 | var x = InteropHelper.Pin(result, h); 38 | var t = InteropHelper.Pin(w, h); 39 | 40 | try 41 | { 42 | // x = b(p) 43 | if (NativeMethods.cs_ci_ipvec(N.pinv, b, t, n) == 0) return; 44 | 45 | // x = L\x 46 | if (NativeMethods.cs_ci_lsolve(N.L, t) == 0) return; 47 | 48 | // x = U\x 49 | if (NativeMethods.cs_ci_usolve(N.U, t) == 0) return; 50 | 51 | // b(q) = x 52 | if (NativeMethods.cs_ci_pvec(S.q, t, x, n) == 0) return; 53 | } 54 | finally 55 | { 56 | InteropHelper.Free(h); 57 | } 58 | } 59 | 60 | protected override int DoFactorize() 61 | { 62 | var h = new List(); 63 | var A = CreateSparse(matrix, h); 64 | 65 | try 66 | { 67 | int order = (int)ordering; 68 | 69 | // ordering and symbolic analysis 70 | var pS = NativeMethods.cs_ci_sqr(order, ref A, 0); 71 | 72 | if (pS == IntPtr.Zero) 73 | { 74 | return -1; 75 | } 76 | 77 | S = Marshal.PtrToStructure(pS); 78 | 79 | // numeric LU factorization 80 | var pN = NativeMethods.cs_ci_lu(ref A, ref S, tol); 81 | 82 | if (pN == IntPtr.Zero) 83 | { 84 | return -1; 85 | } 86 | 87 | N = Marshal.PtrToStructure(pN); 88 | } 89 | finally 90 | { 91 | InteropHelper.Free(h); 92 | } 93 | 94 | return 0; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Factorization/SuiteSparse/Cholmod.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.SuiteSparse.Cholmod; 5 | using CSparse.Storage; 6 | using System.Collections.Generic; 7 | using System.Numerics; 8 | using System.Runtime.InteropServices; 9 | 10 | /// 11 | /// CHOLMOD wrapper. 12 | /// 13 | public class Cholmod : CholmodContext 14 | { 15 | private double[] buffer; 16 | 17 | /// 18 | /// Initializes a new instance of the Cholmod class. 19 | /// 20 | public Cholmod(CompressedColumnStorage matrix) 21 | : base(matrix) 22 | { 23 | } 24 | 25 | /// 26 | public override void Solve(Complex[] input, Complex[] result) 27 | { 28 | Solve(new DenseMatrix(matrix.RowCount, 1, input), new DenseMatrix(matrix.ColumnCount, 1, result)); 29 | } 30 | 31 | protected override CholmodDense CreateDense(DenseColumnMajorStorage matrix, List handles) 32 | { 33 | return CholmodHelper.CreateDense(matrix, handles); 34 | } 35 | 36 | protected override CholmodSparse CreateSparse(CompressedColumnStorage matrix, List handles) 37 | { 38 | // TODO: Stype this should be configurable! 39 | return CholmodHelper.CreateSparse(matrix, Stype.Upper, handles); 40 | } 41 | 42 | protected override void CopyDense(CholmodDense dense, DenseColumnMajorStorage matrix) 43 | { 44 | CholmodHelper.CopyArray(2 * (int)dense.nzmax, dense.x, matrix.Values, ref buffer); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Factorization/SuiteSparse/CholmodHelper.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.Common; 5 | using CSparse.Interop.SuiteSparse.Cholmod; 6 | using CSparse.Storage; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Numerics; 10 | using System.Runtime.InteropServices; 11 | 12 | internal static class CholmodHelper 13 | { 14 | public static CompressedColumnStorage GetSparseMatrix(CholmodSparse sparse, ref double[] buffer) 15 | { 16 | int rows = (int)sparse.nrow; 17 | int columns = (int)sparse.ncol; 18 | 19 | var matrix = new SparseMatrix(rows, columns); 20 | 21 | var ap = new int[sparse.ncol + 1]; 22 | 23 | Marshal.Copy(sparse.p, ap, 0, columns + 1); 24 | 25 | int nnz = ap[columns]; 26 | 27 | var ai = new int[nnz]; 28 | var ax = new Complex[nnz]; 29 | 30 | Marshal.Copy(sparse.i, ai, 0, nnz); 31 | CopyArray(2 * (int)sparse.nzmax, sparse.x, matrix.Values, ref buffer); 32 | 33 | matrix.ColumnPointers = ap; 34 | matrix.RowIndices = ai; 35 | matrix.Values = ax; 36 | 37 | return matrix; 38 | } 39 | 40 | public static DenseColumnMajorStorage GetDenseMatrix(CholmodDense dense, ref double[] buffer) 41 | { 42 | int rows = (int)dense.nrow; 43 | int columns = (int)dense.ncol; 44 | 45 | var matrix = new DenseMatrix(rows, columns); 46 | 47 | CopyArray(2 * (int)dense.nzmax, dense.x, matrix.Values, ref buffer); 48 | 49 | return matrix; 50 | } 51 | 52 | public static CholmodDense CreateDense(DenseColumnMajorStorage matrix, List handles) 53 | { 54 | var A = new CholmodDense(); 55 | 56 | A.nrow = (uint)matrix.RowCount; 57 | A.ncol = (uint)matrix.ColumnCount; 58 | A.nzmax = (uint)(matrix.RowCount * matrix.ColumnCount); 59 | 60 | A.dtype = Dtype.Double; 61 | A.xtype = Xtype.Complex; 62 | 63 | A.x = InteropHelper.Pin(matrix.Values, handles); 64 | A.z = IntPtr.Zero; 65 | A.d = (uint)matrix.RowCount; // TODO: cholmod_dense leading dimension? 66 | 67 | return A; 68 | } 69 | 70 | public static CholmodSparse CreateSparse(CompressedColumnStorage matrix, Stype stype, List handles) 71 | { 72 | var A = new CholmodSparse(); 73 | 74 | A.nrow = (uint)matrix.RowCount; 75 | A.ncol = (uint)matrix.ColumnCount; 76 | 77 | A.dtype = Dtype.Double; 78 | A.xtype = Xtype.Complex; 79 | A.stype = stype; 80 | 81 | A.itype = Constants.CHOLMOD_INT; 82 | 83 | A.nzmax = (uint)matrix.Values.Length; 84 | A.packed = 1; 85 | A.sorted = 1; 86 | 87 | A.nz = IntPtr.Zero; 88 | A.p = InteropHelper.Pin(matrix.ColumnPointers, handles); 89 | A.i = InteropHelper.Pin(matrix.RowIndices, handles); 90 | A.x = InteropHelper.Pin(matrix.Values, handles); 91 | A.z = IntPtr.Zero; 92 | 93 | return A; 94 | } 95 | 96 | public static void CopyArray(int count, IntPtr source, Complex[] target, ref double[] buffer) 97 | { 98 | if (buffer == null || buffer.Length < count) 99 | { 100 | buffer = new double[count]; 101 | } 102 | 103 | Marshal.Copy(source, buffer, 0, count); 104 | 105 | count = count / 2; 106 | 107 | for (int i = 0; i < count; i++) 108 | { 109 | target[i] = new Complex(buffer[2 * i], buffer[2 * i + 1]); 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Factorization/SuiteSparse/SPQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.SuiteSparse.Cholmod; 5 | using CSparse.Interop.SuiteSparse.SPQR; 6 | using CSparse.Storage; 7 | using System.Collections.Generic; 8 | using System.Numerics; 9 | using System.Runtime.InteropServices; 10 | 11 | /// 12 | /// SPQR wrapper. 13 | /// 14 | public class SPQR : SpqrContext 15 | { 16 | private double[] buffer; 17 | 18 | /// 19 | /// Initializes a new instance of the SPQR class. 20 | /// 21 | public SPQR(CompressedColumnStorage matrix) 22 | : base(matrix) 23 | { 24 | } 25 | 26 | /// 27 | public override void Solve(Complex[] input, Complex[] result) 28 | { 29 | Solve(new DenseMatrix(matrix.RowCount, 1, input), new DenseMatrix(matrix.ColumnCount, 1, result)); 30 | } 31 | 32 | protected override CholmodDense CreateDense(DenseColumnMajorStorage matrix, List handles) 33 | { 34 | return CholmodHelper.CreateDense(matrix, handles); 35 | } 36 | 37 | protected override CholmodSparse CreateSparse(CompressedColumnStorage matrix, List handles) 38 | { 39 | return CholmodHelper.CreateSparse(matrix, Stype.General, handles); 40 | } 41 | 42 | protected override void CopyDense(CholmodDense dense, DenseColumnMajorStorage matrix) 43 | { 44 | CholmodHelper.CopyArray(2 * (int)dense.nzmax, dense.x, matrix.Values, ref buffer); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Solver/ArpackResult.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Solver 3 | { 4 | using CSparse.Interop.ARPACK; 5 | using CSparse.Storage; 6 | using System.Numerics; 7 | 8 | /// 9 | public class ArpackResult : ArpackResult 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The number of eigenvalues requested. 15 | /// The problem size. 16 | /// A value, indicating whether eigenvectors are requested. 17 | public ArpackResult(int k, int size, bool computeEigenVectors) 18 | : base(k, size) 19 | { 20 | CreateWorkspace(computeEigenVectors); 21 | } 22 | 23 | /// 24 | public override double[] EigenValuesReal() 25 | { 26 | int k = this.Count; 27 | 28 | var result = new double[k]; 29 | 30 | var e = this.CreateEigenValuesArray(); 31 | 32 | for (int i = 0; i < k; i++) 33 | { 34 | result[i] = e[i].Real; 35 | } 36 | 37 | return result; 38 | } 39 | 40 | /// 41 | public override Matrix EigenVectorsReal() 42 | { 43 | int k = this.Count; 44 | 45 | var result = new Double.DenseMatrix(size, k); 46 | 47 | var e = this.CreateEigenVectorsMatrix(); 48 | 49 | for (int i = 0; i < k; i++) 50 | { 51 | for (int j = 0; j < size; j++) 52 | { 53 | result.At(i, j, e.At(i, j).Real); 54 | } 55 | } 56 | 57 | return result; 58 | } 59 | 60 | /// 61 | protected override Complex[] CreateEigenValuesArray() 62 | { 63 | return (Complex[])eigvalr; 64 | } 65 | 66 | /// 67 | protected override Matrix CreateEigenVectorsMatrix() 68 | { 69 | return new DenseMatrix(size, this.Count, (Complex[])eigvec); 70 | } 71 | 72 | private void CreateWorkspace(bool computeEigenVectors) 73 | { 74 | int k = this.Count; 75 | 76 | // For complex matrices all eigenvalues are stored in 77 | // eigvalr with interleaved real and imaginary part. 78 | 79 | eigvalr = new Complex[k]; 80 | 81 | if (computeEigenVectors) 82 | { 83 | eigvec = new Complex[k * size]; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /CSparse.Interop/Complex/Solver/FeastResult.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Complex.Solver 3 | { 4 | using CSparse.Interop.MKL.Feast; 5 | using CSparse.Storage; 6 | using System.Numerics; 7 | 8 | public class FeastResult : FeastResult 9 | { 10 | /// 11 | public FeastResult(int info, int k, int size, int loops, double error, int m, double[] e, DenseColumnMajorStorage x, double[] r) 12 | : base(info, k, size, loops, error, m, e, x, r) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/CUDA/CudaCholesky.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.CUDA 3 | { 4 | using CSparse.Interop.CUDA; 5 | using CSparse.Storage; 6 | using System; 7 | 8 | // Based on low level interface example cuSolverSp_LowlevelCholesky 9 | 10 | public class CudaCholesky : CuSolverContext 11 | { 12 | private IntPtr _info; 13 | 14 | private bool disposed = false; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The . 20 | /// The sparse matrix. 21 | public CudaCholesky(CudaStream stream, CompressedColumnStorage A) 22 | : this(stream, A, true) 23 | { 24 | } 25 | 26 | /// 27 | /// Initializes a new instance of the class. 28 | /// 29 | /// The . 30 | /// The sparse matrix. 31 | /// A value indicating, whether the storage should be transposed. 32 | public CudaCholesky(CudaStream stream, CompressedColumnStorage A, bool transpose) 33 | : base(stream, A, transpose) 34 | { 35 | } 36 | 37 | ~CudaCholesky() 38 | { 39 | Dispose(false); 40 | } 41 | 42 | protected override SolverStatus Solve(int rows, int columns) 43 | { 44 | return NativeMethods.cusolverSpDcsrcholSolve(_p, rows, d_b, d_x, _info, _buffer); 45 | } 46 | 47 | public override bool Singular(double tol) 48 | { 49 | int singularity = 0; 50 | 51 | // Check if the matrix is singular. 52 | Check(NativeMethods.cusolverSpDcsrcholZeroPivot(_p, _info, tol, ref singularity)); 53 | 54 | return singularity >= 0; 55 | } 56 | 57 | protected override void Factorize(int rows, int columns, int nnz, CuSparseContext A) 58 | { 59 | var ap = A.ColumnPointers; 60 | var ai = A.RowIndices; 61 | var ax = A.Values; 62 | 63 | var desc = A.MatrixDescriptor; 64 | 65 | // Analyze chol(A) to know structure of L. 66 | Check(NativeMethods.cusolverSpXcsrcholAnalysis(_p, rows, nnz, desc, ap, ai, _info)); 67 | 68 | int size_internal = 0, size_chol = 0; 69 | 70 | // Workspace for chol(A). 71 | Check(NativeMethods.cusolverSpDcsrcholBufferInfo(_p, rows, nnz, desc, ax, ap, ai, _info, 72 | ref size_internal, ref size_chol)); 73 | 74 | 75 | Cuda.Malloc(ref _buffer, sizeof(char) * size_chol); 76 | 77 | // Compute A = L*L^T. 78 | Check(NativeMethods.cusolverSpDcsrcholFactor(_p, rows, nnz, desc, ax, ap, ai, _info, _buffer)); 79 | } 80 | 81 | protected override void PrepareFactorize() 82 | { 83 | // Create opaque info structure. 84 | Check(NativeMethods.cusolverSpCreateCsrcholInfo(ref _info)); 85 | } 86 | 87 | protected override void Dispose(bool disposing) 88 | { 89 | if (disposed) return; 90 | 91 | if (_info != IntPtr.Zero) 92 | { 93 | Check(NativeMethods.cusolverSpDestroyCsrcholInfo(_info)); 94 | _info = IntPtr.Zero; 95 | } 96 | 97 | disposed = true; 98 | 99 | base.Dispose(disposing); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/CUDA/CudaQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.CUDA 3 | { 4 | using CSparse.Interop.CUDA; 5 | using CSparse.Storage; 6 | using System; 7 | 8 | // Based on low level interface example cuSolverSp_LowlevelQR 9 | 10 | public class CudaQR : CuSolverContext 11 | { 12 | private IntPtr _info; 13 | 14 | private bool disposed = false; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The . 20 | /// The sparse matrix. 21 | public CudaQR(CudaStream stream, CompressedColumnStorage A) 22 | : this(stream, A, true) 23 | { 24 | } 25 | 26 | /// 27 | /// Initializes a new instance of the class. 28 | /// 29 | /// The . 30 | /// The sparse matrix. 31 | /// A value indicating, whether the storage should be transposed. 32 | public CudaQR(CudaStream stream, CompressedColumnStorage A, bool transpose) 33 | : base(stream, A, transpose) 34 | { 35 | } 36 | 37 | ~CudaQR() 38 | { 39 | Dispose(false); 40 | } 41 | 42 | protected override SolverStatus Solve(int rows, int columns) 43 | { 44 | return NativeMethods.cusolverSpDcsrqrSolve(_p, rows, columns, d_b, d_x, _info, _buffer); 45 | } 46 | 47 | public override bool Singular(double tol) 48 | { 49 | int singularity = 0; 50 | 51 | // Check if the matrix is singular. 52 | Check(NativeMethods.cusolverSpDcsrqrZeroPivot(_p, _info, tol, ref singularity)); 53 | 54 | return singularity >= 0; 55 | } 56 | 57 | protected override void Factorize(int rows, int columns, int nnz, CuSparseContext A) 58 | { 59 | var ap = A.ColumnPointers; 60 | var ai = A.RowIndices; 61 | var ax = A.Values; 62 | 63 | var desc = A.MatrixDescriptor; 64 | 65 | // Analyze qr(A) to know structure of L. 66 | Check(NativeMethods.cusolverSpXcsrqrAnalysis(_p, rows, columns, nnz, desc, ap, ai, _info)); 67 | 68 | int size_internal = 0, size_qr = 0; 69 | 70 | // Workspace for qr(A). 71 | Check(NativeMethods.cusolverSpDcsrqrBufferInfo(_p, rows, columns, nnz, desc, ax, ap, ai, _info, 72 | ref size_internal, ref size_qr)); 73 | 74 | Cuda.Malloc(ref _buffer, sizeof(char) * size_qr); 75 | 76 | Check(NativeMethods.cusolverSpDcsrqrSetup(_p, rows, columns, nnz, desc, ax, ap, ai, 0.0, _info)); 77 | 78 | // Compute A = Q*R. 79 | Check(NativeMethods.cusolverSpDcsrqrFactor(_p, rows, columns, nnz, IntPtr.Zero, IntPtr.Zero, _info, _buffer)); 80 | } 81 | 82 | protected override void PrepareFactorize() 83 | { 84 | // Create opaque info structure. 85 | Check(NativeMethods.cusolverSpCreateCsrqrInfo(ref _info)); 86 | } 87 | 88 | protected override void Dispose(bool disposing) 89 | { 90 | if (disposed) return; 91 | 92 | if (_info != IntPtr.Zero) 93 | { 94 | Check(NativeMethods.cusolverSpDestroyCsrqrInfo(_info)); 95 | _info = IntPtr.Zero; 96 | } 97 | 98 | disposed = true; 99 | 100 | base.Dispose(disposing); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/MKL/Pardiso.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.MKL 3 | { 4 | using CSparse.Interop.MKL.Pardiso; 5 | using CSparse.Storage; 6 | using System; 7 | 8 | /// 9 | /// PARDISO wrapper. 10 | /// 11 | public class Pardiso : PardisoContext 12 | { 13 | /// 14 | /// Initializes a new instance of the Pardiso class. 15 | /// 16 | public Pardiso(CompressedColumnStorage matrix) 17 | : base(matrix, PardisoMatrixType.RealNonsymmetric) 18 | { 19 | } 20 | 21 | /// 22 | /// Initializes a new instance of the Pardiso class. 23 | /// 24 | public Pardiso(CompressedColumnStorage matrix, int mtype) 25 | : base(matrix, mtype) 26 | { 27 | switch (mtype) 28 | { 29 | case PardisoMatrixType.RealNonsymmetric: 30 | case PardisoMatrixType.RealStructurallySymmetric: 31 | case PardisoMatrixType.RealSymmetricIndefinite: 32 | case PardisoMatrixType.RealSymmetricPositiveDefinite: 33 | break; 34 | default: 35 | throw new ArgumentException("Invalid matrix type: expected real.", "mtype"); 36 | } 37 | } 38 | 39 | /// 40 | protected override void Solve(int sys, double[] input, double[] result) 41 | { 42 | Solve(sys, new DenseMatrix(matrix.RowCount, 1, input), new DenseMatrix(matrix.ColumnCount, 1, result)); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/MKL/SparseQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.MKL 3 | { 4 | using CSparse.Interop.Common; 5 | using CSparse.Interop.MKL; 6 | using CSparse.Interop.MKL.SparseQR; 7 | using CSparse.Storage; 8 | using System; 9 | 10 | /// 11 | /// SparseQR wrapper. 12 | /// 13 | public class SparseQR : SparseQRContext 14 | { 15 | /// 16 | /// Initializes a new instance of the SparseQR class. 17 | /// 18 | public SparseQR(CompressedColumnStorage matrix) 19 | : base(new CompressedRowStorage(matrix)) 20 | { 21 | } 22 | 23 | /// 24 | /// Initializes a new instance of the SparseQR class. 25 | /// 26 | public SparseQR(CompressedRowStorage matrix) 27 | : base(matrix) 28 | { 29 | } 30 | 31 | /// 32 | public override void Solve(double[] input, double[] result) 33 | { 34 | var b = new DenseMatrix(matrix.RowCount, 1, input); 35 | var x = new DenseMatrix(matrix.ColumnCount, 1, result); 36 | Solve(b, x); 37 | } 38 | 39 | protected override SparseStatus DoInitialize(CompressedRowStorage matrix) 40 | { 41 | descr.type = SparseMatrixType.General; 42 | 43 | var ap = InteropHelper.Pin(matrix.RowPointers, handles); 44 | var ai = InteropHelper.Pin(matrix.ColumnIndices, handles); 45 | var ax = InteropHelper.Pin(matrix.Values, handles); 46 | 47 | return NativeMethods.mkl_sparse_d_create_csr(ref csrA, SparseIndexBase.Zero, matrix.RowCount, matrix.ColumnCount, ap, IntPtr.Add(ap, Constants.SizeOfInt), ai, ax); 48 | } 49 | 50 | protected override SparseStatus DoFactorize() 51 | { 52 | return NativeMethods.mkl_sparse_d_qr_factorize(csrA, IntPtr.Zero); 53 | } 54 | 55 | protected override SparseStatus DoSolve(IntPtr A, int columns, IntPtr x, int ldx, IntPtr b, int ldb) 56 | { 57 | // We assume type of x and b is DenseColumnMajorStorage. 58 | var denseLayout = SparseLayout.ColumnMajor; 59 | 60 | return NativeMethods.mkl_sparse_d_qr_solve(SparseOperation.NonTranspose, csrA, IntPtr.Zero, denseLayout, columns, x, ldx, b, ldb); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/SuiteSparse/CXSparseCholesky.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.Common; 5 | using CSparse.Interop.SuiteSparse.CXSparse; 6 | using CSparse.Storage; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Runtime.InteropServices; 10 | 11 | public class CXSparseCholesky : CXSparseContext 12 | { 13 | /// 14 | /// Initializes a new instance of the SuperLU class. 15 | /// 16 | public CXSparseCholesky(CompressedColumnStorage matrix, ColumnOrdering ordering) 17 | : base(matrix, ordering) 18 | { 19 | } 20 | 21 | public override void Solve(double[] input, double[] result) 22 | { 23 | if (!factorized && DoFactorize() != 0) 24 | { 25 | throw new Exception(); // TODO: exception 26 | } 27 | 28 | var n = matrix.RowCount; 29 | 30 | var h = new List(); 31 | 32 | var b = InteropHelper.Pin(input, h); 33 | var x = InteropHelper.Pin(result, h); 34 | var t = InteropHelper.Pin(w, h); 35 | 36 | try 37 | { 38 | // x = P*b 39 | if (NativeMethods.cs_di_ipvec(S.pinv, b, t, n) == 0) return; 40 | 41 | // x = L\x 42 | if (NativeMethods.cs_di_lsolve(N.L, t) == 0) return; 43 | 44 | // x = L'\x 45 | if (NativeMethods.cs_di_ltsolve(N.L, t) == 0) return; 46 | 47 | // b = P'*x 48 | if (NativeMethods.cs_di_pvec(S.pinv, t, x, n) == 0) return; 49 | } 50 | finally 51 | { 52 | InteropHelper.Free(h); 53 | } 54 | } 55 | 56 | protected override int DoFactorize() 57 | { 58 | var h = new List(); 59 | var A = CreateSparse(matrix, h); 60 | 61 | try 62 | { 63 | int order = (int)ordering; 64 | 65 | // ordering and symbolic analysis 66 | var pS = NativeMethods.cs_di_schol(order, ref A); 67 | 68 | if (pS == IntPtr.Zero) 69 | { 70 | return -1; 71 | } 72 | 73 | S = Marshal.PtrToStructure(pS); 74 | 75 | // numeric Cholesky factorization 76 | var pN = NativeMethods.cs_di_chol(ref A, ref S); 77 | 78 | if (pN == IntPtr.Zero) 79 | { 80 | return -1; 81 | } 82 | 83 | N = Marshal.PtrToStructure(pN); 84 | } 85 | finally 86 | { 87 | InteropHelper.Free(h); 88 | } 89 | 90 | return 0; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/SuiteSparse/CXSparseLU.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.Common; 5 | using CSparse.Interop.SuiteSparse.CXSparse; 6 | using CSparse.Storage; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Runtime.InteropServices; 10 | 11 | public class CXSparseLU : CXSparseContext 12 | { 13 | private readonly double tol; 14 | 15 | /// 16 | /// Initializes a new instance of the SuperLU class. 17 | /// 18 | public CXSparseLU(CompressedColumnStorage matrix, ColumnOrdering ordering, double tol) 19 | : base(matrix, ordering) 20 | { 21 | this.tol = tol; 22 | } 23 | 24 | public override void Solve(double[] input, double[] result) 25 | { 26 | if (!factorized && DoFactorize() != 0) 27 | { 28 | throw new Exception(); // TODO: exception 29 | } 30 | 31 | var n = matrix.RowCount; 32 | 33 | var h = new List(); 34 | 35 | var b = InteropHelper.Pin(input, h); 36 | var x = InteropHelper.Pin(result, h); 37 | var t = InteropHelper.Pin(w, h); 38 | 39 | try 40 | { 41 | // x = b(p) 42 | if (NativeMethods.cs_di_ipvec(N.pinv, b, t, n) == 0) return; 43 | 44 | // x = L\x 45 | if (NativeMethods.cs_di_lsolve(N.L, t) == 0) return; 46 | 47 | // x = U\x 48 | if (NativeMethods.cs_di_usolve(N.U, t) == 0) return; 49 | 50 | // b(q) = x 51 | if (NativeMethods.cs_di_pvec(S.q, t, x, n) == 0) return; 52 | } 53 | finally 54 | { 55 | InteropHelper.Free(h); 56 | } 57 | } 58 | 59 | protected override int DoFactorize() 60 | { 61 | var h = new List(); 62 | var A = CreateSparse(matrix, h); 63 | 64 | try 65 | { 66 | int order = (int)ordering; 67 | 68 | // ordering and symbolic analysis 69 | var pS = NativeMethods.cs_di_sqr(order, ref A, 0); 70 | 71 | if (pS == IntPtr.Zero) 72 | { 73 | return -1; 74 | } 75 | 76 | S = Marshal.PtrToStructure(pS); 77 | 78 | // numeric LU factorization 79 | var pN = NativeMethods.cs_di_lu(ref A, ref S, tol); 80 | 81 | if (pN == IntPtr.Zero) 82 | { 83 | return -1; 84 | } 85 | 86 | N = Marshal.PtrToStructure(pN); 87 | } 88 | finally 89 | { 90 | InteropHelper.Free(h); 91 | } 92 | 93 | return 0; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/SuiteSparse/Cholmod.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.SuiteSparse.Cholmod; 5 | using CSparse.Storage; 6 | using System.Collections.Generic; 7 | using System.Runtime.InteropServices; 8 | 9 | /// 10 | /// CHOLMOD wrapper. 11 | /// 12 | public class Cholmod : CholmodContext 13 | { 14 | /// 15 | /// Initializes a new instance of the Cholmod class. 16 | /// 17 | public Cholmod(CompressedColumnStorage matrix) 18 | : base(matrix) 19 | { 20 | } 21 | 22 | /// 23 | public override void Solve(double[] input, double[] result) 24 | { 25 | Solve(new DenseMatrix(matrix.RowCount, 1, input), new DenseMatrix(matrix.ColumnCount, 1, result)); 26 | } 27 | 28 | protected override CholmodDense CreateDense(DenseColumnMajorStorage matrix, List handles) 29 | { 30 | return CholmodHelper.CreateDense(matrix, handles); 31 | } 32 | 33 | protected override CholmodSparse CreateSparse(CompressedColumnStorage matrix, List handles) 34 | { 35 | // TODO: Stype this should be configurable! 36 | return CholmodHelper.CreateSparse(matrix, Stype.Upper, handles); 37 | } 38 | 39 | protected override void CopyDense(CholmodDense dense, DenseColumnMajorStorage matrix) 40 | { 41 | Marshal.Copy(dense.x, matrix.Values, 0, (int)dense.nzmax); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/SuiteSparse/CholmodHelper.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.SuiteSparse.Cholmod; 5 | using CSparse.Interop.Common; 6 | using CSparse.Storage; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Runtime.InteropServices; 10 | 11 | internal static class CholmodHelper 12 | { 13 | public static CompressedColumnStorage GetSparseMatrix(CholmodSparse sparse) 14 | { 15 | int rows = (int)sparse.nrow; 16 | int columns = (int)sparse.ncol; 17 | 18 | var matrix = new SparseMatrix(rows, columns); 19 | 20 | var ap = new int[sparse.ncol + 1]; 21 | 22 | Marshal.Copy(sparse.p, ap, 0, columns + 1); 23 | 24 | int nnz = ap[columns]; 25 | 26 | var ai = new int[nnz]; 27 | var ax = new double[nnz]; 28 | 29 | Marshal.Copy(sparse.i, ai, 0, nnz); 30 | Marshal.Copy(sparse.x, ax, 0, nnz); 31 | 32 | matrix.ColumnPointers = ap; 33 | matrix.RowIndices = ai; 34 | matrix.Values = ax; 35 | 36 | return matrix; 37 | } 38 | 39 | public static DenseColumnMajorStorage GetDenseMatrix(CholmodDense dense) 40 | { 41 | int rows = (int)dense.nrow; 42 | int columns = (int)dense.ncol; 43 | 44 | var matrix = new DenseMatrix(rows, columns); 45 | 46 | Marshal.Copy(dense.x, matrix.Values, 0, rows * columns); 47 | 48 | return matrix; 49 | } 50 | 51 | public static CholmodDense CreateDense(DenseColumnMajorStorage matrix, List handles) 52 | { 53 | var A = new CholmodDense(); 54 | 55 | A.nrow = (uint)matrix.RowCount; 56 | A.ncol = (uint)matrix.ColumnCount; 57 | A.nzmax = (uint)(matrix.RowCount * matrix.ColumnCount); 58 | 59 | A.dtype = Dtype.Double; 60 | A.xtype = Xtype.Real; 61 | 62 | A.x = InteropHelper.Pin(matrix.Values, handles); 63 | A.z = IntPtr.Zero; 64 | A.d = (uint)matrix.RowCount; // TODO: cholmod_dense leading dimension? 65 | 66 | return A; 67 | } 68 | 69 | public static CholmodSparse CreateSparse(CompressedColumnStorage matrix, Stype stype, List handles) 70 | { 71 | var A = new CholmodSparse(); 72 | 73 | A.nrow = (uint)matrix.RowCount; 74 | A.ncol = (uint)matrix.ColumnCount; 75 | 76 | A.dtype = Dtype.Double; 77 | A.xtype = Xtype.Real; 78 | A.stype = stype; 79 | 80 | A.itype = Constants.CHOLMOD_INT; 81 | 82 | A.nzmax = (uint)matrix.Values.Length; 83 | A.packed = 1; 84 | A.sorted = 1; 85 | 86 | A.nz = IntPtr.Zero; 87 | A.p = InteropHelper.Pin(matrix.ColumnPointers, handles); 88 | A.i = InteropHelper.Pin(matrix.RowIndices, handles); 89 | A.x = InteropHelper.Pin(matrix.Values, handles); 90 | A.z = IntPtr.Zero; 91 | 92 | return A; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/SuiteSparse/SPQR.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.SuiteSparse.Cholmod; 5 | using CSparse.Interop.SuiteSparse.SPQR; 6 | using CSparse.Storage; 7 | using System.Collections.Generic; 8 | using System.Runtime.InteropServices; 9 | 10 | /// 11 | /// SPQR wrapper. 12 | /// 13 | public class SPQR : SpqrContext 14 | { 15 | /// 16 | /// Initializes a new instance of the Cholmod class. 17 | /// 18 | public SPQR(CompressedColumnStorage matrix) 19 | : base(matrix) 20 | { 21 | } 22 | 23 | /// 24 | public override void Solve(double[] input, double[] result) 25 | { 26 | Solve(new DenseMatrix(matrix.RowCount, 1, input), new DenseMatrix(matrix.ColumnCount, 1, result)); 27 | } 28 | 29 | protected override CholmodDense CreateDense(DenseColumnMajorStorage matrix, List handles) 30 | { 31 | return CholmodHelper.CreateDense(matrix, handles); 32 | } 33 | 34 | protected override CholmodSparse CreateSparse(CompressedColumnStorage matrix, List handles) 35 | { 36 | return CholmodHelper.CreateSparse(matrix, Stype.General, handles); 37 | } 38 | 39 | protected override void CopyDense(CholmodDense dense, DenseColumnMajorStorage matrix) 40 | { 41 | Marshal.Copy(dense.x, matrix.Values, 0, (int)dense.nzmax); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Factorization/SuiteSparse/Umfpack.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Factorization.SuiteSparse 3 | { 4 | using CSparse.Interop.SuiteSparse.Umfpack; 5 | using CSparse.Storage; 6 | using System; 7 | 8 | /// 9 | /// UMFPACK wrapper. 10 | /// 11 | public class Umfpack : UmfpackContext 12 | { 13 | /// 14 | /// Initializes a new instance of the Umfpack class. 15 | /// 16 | public Umfpack(CompressedColumnStorage matrix) 17 | : base(matrix) 18 | { 19 | } 20 | 21 | /// 22 | public override void GetFactors(out CompressedColumnStorage L, out CompressedColumnStorage U, out int[] P, out int[] Q, out double[] D, out double[] R) 23 | { 24 | if (numeric == IntPtr.Zero) 25 | { 26 | throw new InvalidOperationException("Numeric factorization unavailable."); 27 | } 28 | 29 | int rows = info.NROW; 30 | int cols = info.NCOL; 31 | int inner = Math.Min(rows, cols); 32 | 33 | L = new SparseMatrix(rows, inner, info.LNZ); 34 | U = new SparseMatrix(inner, cols, info.UNZ); 35 | 36 | P = new int[rows]; 37 | Q = new int[cols]; 38 | D = new double[inner]; 39 | R = new double[rows]; 40 | 41 | NativeMethods.umfpack_di_get_numeric(L.ColumnPointers, L.RowIndices, L.Values, U.ColumnPointers, U.RowIndices, U.Values, P, Q, D, out int recip, R, numeric); 42 | } 43 | 44 | protected override void DoInitialize() 45 | { 46 | NativeMethods.umfpack_di_defaults(control.Raw); 47 | } 48 | 49 | protected override int DoSymbolic() 50 | { 51 | return NativeMethods.umfpack_di_symbolic(matrix.RowCount, matrix.ColumnCount, 52 | matrix.ColumnPointers, matrix.RowIndices, matrix.Values, 53 | out symbolic, control.Raw, info.Raw); 54 | } 55 | 56 | protected override int DoNumeric() 57 | { 58 | return NativeMethods.umfpack_di_numeric(matrix.ColumnPointers, matrix.RowIndices, matrix.Values, 59 | symbolic, out numeric, control.Raw, info.Raw); 60 | } 61 | 62 | protected override int DoFactorize() 63 | { 64 | int status = NativeMethods.umfpack_di_symbolic(matrix.RowCount, matrix.ColumnCount, 65 | matrix.ColumnPointers, matrix.RowIndices, matrix.Values, 66 | out symbolic, control.Raw, info.Raw); 67 | 68 | if (status != Constants.UMFPACK_OK) 69 | { 70 | return status; 71 | } 72 | 73 | return NativeMethods.umfpack_di_numeric(matrix.ColumnPointers, matrix.RowIndices, matrix.Values, 74 | symbolic, out numeric, control.Raw, info.Raw); 75 | } 76 | 77 | protected override int DoSolve(UmfpackSolve sys, double[] input, double[] result) 78 | { 79 | return NativeMethods.umfpack_di_solve((int)sys, matrix.ColumnPointers, matrix.RowIndices, matrix.Values, 80 | result, input, numeric, control.Raw, info.Raw); 81 | } 82 | 83 | protected override int DoSolve(UmfpackSolve sys, double[] input, double[] result, int[] wi, double[] wx) 84 | { 85 | return NativeMethods.umfpack_di_wsolve((int)sys, matrix.ColumnPointers, matrix.RowIndices, matrix.Values, 86 | result, input, numeric, control.Raw, info.Raw, wi, wx); 87 | } 88 | 89 | protected override double[] CreateWorkspace(int n, bool refine) 90 | { 91 | return new double[refine ? 5 * n : n]; 92 | } 93 | 94 | protected override void Dispose(bool disposing) 95 | { 96 | if (symbolic != IntPtr.Zero) 97 | { 98 | NativeMethods.umfpack_di_free_symbolic(ref symbolic); 99 | } 100 | 101 | if (numeric != IntPtr.Zero) 102 | { 103 | NativeMethods.umfpack_di_free_numeric(ref numeric); 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Solver/ExtendedEigensolverResult.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Solver 3 | { 4 | using CSparse.Interop.MKL; 5 | using CSparse.Interop.MKL.ExtendedEigensolver; 6 | 7 | public class ExtendedEigensolverResult : ExtendedEigensolverResult 8 | { 9 | double[] eigenvalues; 10 | 11 | Matrix eigenvectors; 12 | 13 | /// 14 | public ExtendedEigensolverResult(SparseStatus info, int size, int k, double[] e, Matrix x, double[] r) 15 | : base(info, size, k, e, x, r) 16 | { 17 | eigenvalues = e; 18 | eigenvectors = x; 19 | } 20 | 21 | /// 22 | public override bool HasEigenVectors => ConvergedEigenValues > 0 && eigenvectors != null; 23 | 24 | /// 25 | public override double[] EigenValuesReal() 26 | { 27 | return eigenvalues; 28 | } 29 | 30 | /// 31 | public override Matrix EigenVectorsReal() 32 | { 33 | return eigenvectors; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /CSparse.Interop/Double/Solver/FeastResult.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Double.Solver 3 | { 4 | using CSparse.Interop.MKL.Feast; 5 | using CSparse.Storage; 6 | 7 | public class FeastResult : FeastResult 8 | { 9 | /// 10 | public FeastResult(int info, int k, int size, int loops, double error, int m, double[] e, DenseColumnMajorStorage x, double[] r) 11 | : base(info, k, size, loops, error, m, e, x, r) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /CSparse.Interop/Factorization/IDisposableSolver.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Factorization 3 | { 4 | using System; 5 | 6 | public interface IDisposableSolver : IDisposable, ISolver 7 | where T : struct, IEquatable, IFormattable 8 | { 9 | /// 10 | /// Gets the non-zeros count of the factors, if available, otherwise -1. 11 | /// 12 | int NonZerosCount { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/CUDA/CuSolverException.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.CUDA 3 | { 4 | using System; 5 | 6 | public class CuSolverException : Exception 7 | { 8 | public SolverStatus Status { get; private set; } 9 | 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// 14 | public CuSolverException(SolverStatus status) 15 | { 16 | Status = status; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /CSparse.Interop/Interop/CUDA/CuSparseException.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.CUDA 3 | { 4 | using System; 5 | 6 | public class CuSparseException : Exception 7 | { 8 | public SparseStatus Status { get; private set; } 9 | 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// 14 | public CuSparseException(SparseStatus status) 15 | { 16 | Status = status; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /CSparse.Interop/Interop/CUDA/Cuda.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using size_t = System.Int32; // TODO: x64 4 | 5 | namespace CSparse.Interop.CUDA 6 | { 7 | public class Cuda 8 | { 9 | /// 10 | /// Initializes the CUDA device with maximum GFLOPS. 11 | /// 12 | /// The CUDA device id. 13 | /// Will throw, if no device is found. 14 | public static int Initialize() 15 | { 16 | return CudaDevice.Initialize(); 17 | } 18 | 19 | /// 20 | /// Returns the requested CUDA device attribute. 21 | /// 22 | /// The . 23 | /// The device id. 24 | /// 25 | public static int GetDeviceAttribute(DeviceAttribute attribute, int device) 26 | { 27 | int value = 0; 28 | 29 | Check(NativeMethods.cudaDeviceGetAttribute(ref value, attribute, device)); 30 | 31 | return value; 32 | } 33 | 34 | public static int GetDriverVersion() 35 | { 36 | int version = 0; 37 | Check(NativeMethods.cudaDriverGetVersion(ref version)); 38 | return version; 39 | } 40 | 41 | public static int GetRuntimeVersion() 42 | { 43 | int version = 0; 44 | Check(NativeMethods.cudaRuntimeGetVersion(ref version)); 45 | return version; 46 | } 47 | 48 | internal static void Malloc(ref IntPtr p, size_t size) 49 | { 50 | Check(NativeMethods.cudaMalloc(ref p, size)); 51 | } 52 | 53 | internal static void CopyToDevice(IntPtr dest, IntPtr src, size_t size) 54 | { 55 | Check(NativeMethods.cudaMemcpy(dest, src, size, MemcpyKind.HostToDevice)); 56 | } 57 | 58 | internal static void CopyToHost(IntPtr dest, IntPtr src, size_t size) 59 | { 60 | Check(NativeMethods.cudaMemcpy(dest, src, size, MemcpyKind.DeviceToHost)); 61 | } 62 | 63 | internal static void Free(IntPtr p) 64 | { 65 | NativeMethods.cudaFree(p); 66 | } 67 | 68 | private static void Check(CudaResult result) 69 | { 70 | if (result != CudaResult.Success) 71 | { 72 | throw new Exception("CudaResult " + result); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/CUDA/CudaException.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.CUDA 3 | { 4 | using System; 5 | 6 | public class CudaException : Exception 7 | { 8 | public CudaResult Result { get; private set; } 9 | 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// 14 | public CudaException(CudaResult result) 15 | { 16 | Result = result; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/CUDA/CudaStream.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.CUDA 3 | { 4 | using System; 5 | 6 | public class CudaStream : IDisposable 7 | { 8 | IntPtr _p; 9 | 10 | public IntPtr Pointer { get { return _p; } } 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public CudaStream() 16 | { 17 | Check(NativeMethods.cudaStreamCreate(ref _p)); 18 | } 19 | 20 | ~CudaStream() 21 | { 22 | Dispose(false); 23 | } 24 | 25 | private void Check(CudaResult result) 26 | { 27 | if (result != CudaResult.Success) 28 | { 29 | throw new CudaException(result); 30 | } 31 | } 32 | 33 | #region IDisposable 34 | 35 | // See https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose 36 | 37 | bool disposed = false; 38 | 39 | public void Dispose() 40 | { 41 | Dispose(true); 42 | GC.SuppressFinalize(this); 43 | } 44 | 45 | protected virtual void Dispose(bool disposing) 46 | { 47 | if (disposed) return; 48 | 49 | // Free unmanaged objects. 50 | 51 | if (_p != IntPtr.Zero) 52 | { 53 | Check(NativeMethods.cudaStreamDestroy(_p)); 54 | _p = IntPtr.Zero; 55 | } 56 | 57 | disposed = true; 58 | } 59 | 60 | #endregion 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/Common/InteropHelper.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.Common 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Runtime.InteropServices; 6 | 7 | internal static class InteropHelper 8 | { 9 | /// 10 | /// Pin given object and add handle to list. 11 | /// 12 | /// Object to pin. 13 | /// List of handles. 14 | /// Address of pinned object. 15 | public static IntPtr Pin(object data, List handles) 16 | { 17 | if (data == null) return IntPtr.Zero; 18 | 19 | var h = GCHandle.Alloc(data, GCHandleType.Pinned); 20 | 21 | handles.Add(h); 22 | 23 | return h.AddrOfPinnedObject(); 24 | } 25 | 26 | /// 27 | /// Free all handles of given list. 28 | /// 29 | /// List of handles. 30 | public static void Free(List handles) 31 | { 32 | if (handles == null) return; 33 | 34 | foreach (var h in handles) 35 | { 36 | h.Free(); 37 | } 38 | 39 | handles.Clear(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/ExtendedEigensolver/ExtendedEigensolverResult.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL.ExtendedEigensolver 3 | { 4 | using CSparse.Solvers; 5 | using System; 6 | using System.Numerics; 7 | 8 | public abstract class ExtendedEigensolverResult : IEigenSolverResult 9 | where T : struct, IEquatable, IFormattable 10 | { 11 | protected int size; 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The status returned by MKL extended eigensolver. 17 | /// The matrix size. 18 | /// The number of eigenvalues found (k < k0). 19 | /// Array of length k0. The first k entries of e are eigenvalues found in the interval. 20 | /// Matrix with k0 columns containing the orthonormal eigenvectors corresponding to the 21 | /// computed eigenvalues e, with the i-th column of x holding the eigenvector associated with e[i]. 22 | /// Array of length k0 containing the relative residual vector (in the first k components). 23 | public ExtendedEigensolverResult(SparseStatus info, int size, int k, double[] e, Matrix x, double[] r) 24 | { 25 | this.size = size; 26 | 27 | Status = info; 28 | 29 | ConvergedEigenValues = k; 30 | Residuals = r; 31 | } 32 | 33 | /// 34 | /// Gets the number of requested eigenvalues (not supported in MKL extended eigensolver). 35 | /// 36 | public int Count => -1; // TODO: remove count property from interface? 37 | 38 | /// 39 | public SparseStatus Status { get; protected set; } 40 | 41 | /// 42 | /// Gets the integer status code returned by MKL extended eigensolver. 43 | /// 44 | public int ErrorCode => (int)Status; 45 | 46 | /// 47 | public int ConvergedEigenValues { get; protected set; } 48 | 49 | /// 50 | public abstract bool HasEigenVectors { get; } 51 | 52 | /// 53 | public Matrix EigenVectors { get; protected set; } 54 | 55 | /// 56 | public Complex[] EigenValues { get; protected set; } 57 | 58 | /// 59 | public double[] Residuals { get; protected set; } 60 | 61 | /// 62 | /// Gets the number of iteration taken (not supported in MKL extended eigensolver). 63 | /// 64 | public int IterationsTaken => -1; 65 | 66 | /// 67 | /// Gets the number of Arnoldi vectors computed (not supported in MKL extended eigensolver). 68 | /// 69 | public int ArnoldiCount => -1; 70 | 71 | /// 72 | /// Throws an , if MKL extended eigensolver failed to solve the problem. 73 | /// 74 | public void EnsureSuccess() 75 | { 76 | if (Status != SparseStatus.Success) 77 | { 78 | throw new Exception(); 79 | } 80 | } 81 | 82 | /// 83 | public abstract double[] EigenValuesReal(); 84 | 85 | /// 86 | public abstract Matrix EigenVectorsReal(); 87 | 88 | protected virtual Complex[] CreateEigenValues(double[] x, int length) 89 | { 90 | var result = new Complex[length]; 91 | 92 | for (int i = 0; i < length; i++) 93 | { 94 | result[i] = x[i]; 95 | } 96 | 97 | return result; 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/Feast/FeastException.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL.Feast 3 | { 4 | using System; 5 | 6 | public class FeastException : Exception 7 | { 8 | public int ErrorCode { get; private set; } 9 | 10 | public FeastException(int code) 11 | : base(GetErrorMessage(code)) 12 | { 13 | this.ErrorCode = code; 14 | } 15 | 16 | private static string GetErrorMessage(int code) 17 | { 18 | switch (code) 19 | { 20 | case 1: 21 | return "Warning: No eigenvalue found in the search interval."; 22 | case 2: 23 | return "Warning: No Convergence (increase number of iteration loops)."; // #iteration loops>fpm(4) 24 | case 3: 25 | return "Warning: Size of the subspace m0 is too small (m0 < m)."; 26 | case 4: 27 | return "Successful return of only the computed subspace after call with fpm[13]=1"; 28 | case 5: 29 | return "Successful return of only stochastic estimation of number of eigenvalues after call with fpm[13]=2"; 30 | case 6: 31 | return "FEAST converges but subspace is not bi-orthonormal"; 32 | case 200: 33 | return "Problem with emin, emax (emin >= emax)."; 34 | case 201: 35 | return "Problem with size of initial subspace m0 (m0 <= 0 or m0 > n)."; 36 | case 202: 37 | return "Problem with size of the system n (n <= 0)."; 38 | case -1: 39 | return "Internal error for allocation memory."; 40 | case -2: 41 | return "Internal error of the inner system solver. Possible reasons: not enough memory for inner linear system solver or inconsistent input."; 42 | case -3: 43 | return "Internal error of the reduced eigenvalue solver. Possible cause: matrix B may not be positive definite."; 44 | case -4: 45 | return "Matrix B is not positive definite."; 46 | default: 47 | break; 48 | } 49 | 50 | if (code >= 100) 51 | { 52 | return "Problem with i-th value of the input FEAST parameter (fpm[" + (code % 100) + "]."; 53 | } 54 | 55 | if (code <= -100) 56 | { 57 | return "Problem with the i-th argument of the FEAST interface (" + (-code % 100) + ")."; 58 | } 59 | 60 | return "Unknown error."; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/Feast/FeastResult.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL.Feast 3 | { 4 | using CSparse.Storage; 5 | using System; 6 | using System.Numerics; 7 | 8 | /// 9 | /// FEAST result. 10 | /// 11 | public abstract class FeastResult 12 | where T : struct, IEquatable, IFormattable 13 | { 14 | protected int size; 15 | 16 | /// 17 | /// Initializes a new instance of the FeastResult class. 18 | /// 19 | /// The status returned by FEAST. 20 | /// The number of eigenvalues requested. 21 | /// The matrix size. 22 | /// The number of refinement loops executed. 23 | /// The relative error on the trace. 24 | /// The number of eigenvalues found (m < m0). 25 | /// Array of length m0. The first m entries of e are eigenvalues found in the interval. 26 | /// Matrix with m0 columns containing the orthonormal eigenvectors corresponding to the 27 | /// computed eigenvalues e, with the i-th column of x holding the eigenvector associated with e[i]. 28 | /// Array of length m0 containing the relative residual vector (in the first m components). 29 | public FeastResult(int info, int m0, int size, int loops, double error, int m, double[] e, DenseColumnMajorStorage x, double[] r) 30 | { 31 | this.size = size; 32 | 33 | Status = info; 34 | SubspaceDimension = m0; 35 | RefinementLoops = loops; 36 | RelativeTraceError = error; 37 | 38 | ConvergedEigenvalues = m; 39 | 40 | EigenValues = CreateEigenValues(e, m); 41 | EigenVectors = x; 42 | 43 | RelativeResiduals = r; 44 | } 45 | 46 | /// 47 | /// Gets the status code returned by FEAST. 48 | /// 49 | public int Status { get; protected set; } 50 | 51 | /// 52 | /// Gets the subspace dimension. 53 | /// 54 | public int SubspaceDimension { get; protected set; } 55 | 56 | /// 57 | /// Gets the number of refinement loop executed. 58 | /// 59 | public int RefinementLoops { get; protected set; } 60 | 61 | /// 62 | /// Gets the relative error on the trace. 63 | /// 64 | public double RelativeTraceError { get; protected set; } 65 | 66 | /// 67 | /// Gets the number of converged eigenvalues. 68 | /// 69 | public int ConvergedEigenvalues { get; protected set; } 70 | 71 | /// 72 | /// Gets the dense matrix of eigenvectors stored in column major order. 73 | /// 74 | public DenseColumnMajorStorage EigenVectors { get; protected set; } 75 | 76 | /// 77 | /// Gets the eigenvalues. 78 | /// 79 | public Complex[] EigenValues { get; protected set; } 80 | 81 | /// 82 | /// Gets the relative residuals vector. 83 | /// 84 | public double[] RelativeResiduals { get; protected set; } 85 | 86 | protected virtual Complex[] CreateEigenValues(double[] x, int length) 87 | { 88 | var result = new Complex[length]; 89 | 90 | for (int i = 0; i < length; i++) 91 | { 92 | result[i] = x[i]; 93 | } 94 | 95 | return result; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/Helper.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL 3 | { 4 | using System; 5 | using System.Text; 6 | 7 | public static class Helper 8 | { 9 | /// 10 | /// The MKL library name used for p/invoke. 11 | /// 12 | public const string LibraryName = "mkl_rt.2"; 13 | 14 | /// 15 | /// Gets the MKL version. 16 | /// 17 | public static Version GetVersion() 18 | { 19 | MKLVersion version = default(MKLVersion); 20 | 21 | // NOTE: leaks memory (char* pointers in MKLVersion struct). 22 | 23 | NativeMethods.mkl_get_version(ref version); 24 | 25 | return new Version(version.MajorVersion, version.MinorVersion, version.BuildNumber); 26 | } 27 | 28 | /// 29 | /// Gets the MKL version string. 30 | /// 31 | public static string GetVersionString() 32 | { 33 | var buffer = new StringBuilder(200); 34 | 35 | NativeMethods.mkl_get_version_string(buffer, 200); 36 | 37 | return buffer.ToString().TrimEnd(); 38 | } 39 | 40 | /// 41 | /// Sets the number of threads to use. 42 | /// 43 | /// The number of threads. 44 | public static void SetNumThreads(int nt) 45 | { 46 | NativeMethods.mkl_set_num_threads(nt); 47 | } 48 | 49 | /// 50 | /// Gets the number of threads targeted for parallelism. 51 | /// 52 | public static int GetMaxThreads() 53 | { 54 | return NativeMethods.mkl_get_max_threads(); 55 | } 56 | 57 | /* 58 | 59 | public static int SetCWBR(CBWR cbwr) 60 | { 61 | return NativeMethods.mkl_cbwr_set((int)cbwr); 62 | } 63 | 64 | public static CBWR GetCWBR() 65 | { 66 | return (CBWR)NativeMethods.mkl_cbwr_get(MKL_CBWR_ALL); 67 | } 68 | 69 | public enum CBWR 70 | { 71 | UNSET_ALL = 0, 72 | OFF = 0, 73 | BRANCH_OFF = 1, 74 | AUTO = 2, 75 | COMPATIBLE = 3, 76 | SSE2 = 4, 77 | SSE3 = 5, 78 | SSSE3 = 6, 79 | SSE4_1 = 7, 80 | SSE4_2 = 8, 81 | AVX = 9, 82 | AVX2 = 10 83 | } 84 | 85 | const int MKL_CBWR_BRANCH = 1; 86 | const int MKL_CBWR_ALL = ~0; 87 | 88 | // error codes 89 | const int CBWR_SUCCESS = 0; 90 | const int CBWR_ERR_INVALID_SETTINGS = -1; 91 | const int CBWR_ERR_INVALID_INPUT = -2; 92 | const int CBWR_ERR_UNSUPPORTED_BRANCH = -3; 93 | const int CBWR_ERR_UNKNOWN_BRANCH = -4; 94 | const int CBWR_ERR_MODE_CHANGE_FAILURE = -8; 95 | 96 | //*/ 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/Pardiso/Constants.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL.Pardiso 3 | { 4 | internal class Constants 5 | { 6 | public const int NonTransposed = 0; 7 | public const int ConjugateTransposed = 1; 8 | public const int Transposed = 2; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/Pardiso/NativeMethods.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL.Pardiso 3 | { 4 | using System; 5 | using System.Runtime.InteropServices; 6 | 7 | // See https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2024-2/onemkl-pardiso-parallel-direct-sparse-solver-iface.html 8 | 9 | internal static class NativeMethods 10 | { 11 | const string DLL = Helper.LibraryName; 12 | 13 | [DllImport(DLL, EntryPoint = "pardisoinit", CallingConvention = CallingConvention.Cdecl)] 14 | public static extern void pardisoinit(IntPtr[] pt, /*const*/ ref int mtype, int[] iparm); 15 | 16 | [DllImport(DLL, EntryPoint = "pardiso", CallingConvention = CallingConvention.Cdecl)] 17 | public static extern void pardiso(IntPtr[] pt, /*const*/ ref int maxfct, /*const*/ ref int mnum, /*const*/ ref int mtype, 18 | /*const*/ ref int phase, /*const*/ ref int n, /*const*/ IntPtr a, /*const*/ IntPtr ia, /*const*/ IntPtr ja, int[] perm, 19 | /*const*/ ref int nrhs, int[] iparm, /*const*/ ref int msglvl, IntPtr b, IntPtr x, out int error); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/Pardiso/PardisoException.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL.Pardiso 3 | { 4 | using System; 5 | 6 | public class PardisoException : Exception 7 | { 8 | public int ErrorCode { get; private set; } 9 | 10 | public PardisoException(int code) 11 | : base(GetErrorMessage(code)) 12 | { 13 | this.ErrorCode = code; 14 | } 15 | 16 | private static string GetErrorMessage(int code) 17 | { 18 | switch (code) 19 | { 20 | case -1: 21 | return "Input inconsistent."; 22 | case -2: 23 | return "Not enough memory."; 24 | case -3: 25 | return "Reordering problem."; 26 | case -4: 27 | return "Zero pivot, numerical factorization or iterative refinement problem."; 28 | case -5: 29 | return "Unclassified (internal) error."; 30 | case -6: 31 | return "Reordering failed (matrix types 11 and 13 only)."; 32 | case -7: 33 | return "Diagonal matrix is singular."; 34 | case -8: 35 | return "32-bit integer overflow problem."; 36 | case -9: 37 | return "Not enough memory for OOC."; 38 | case -10: 39 | return "Problems with opening OOC temporary files."; 40 | case -11: 41 | return "Read/write problems with the OOC data file."; 42 | default: 43 | break; 44 | } 45 | 46 | return "Unknown error."; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/Pardiso/PardisoMatrixType.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL.Pardiso 3 | { 4 | /// 5 | /// PARDISO matrix type. 6 | /// 7 | public class PardisoMatrixType 8 | { 9 | /// 10 | /// Real and structurally symmetric matrix. 11 | /// 12 | public const int RealStructurallySymmetric = 1; 13 | 14 | /// 15 | /// Real and symmetric positive definite matrix. 16 | /// 17 | public const int RealSymmetricPositiveDefinite = 2; 18 | 19 | /// 20 | /// Real and symmetric indefinite matrix. 21 | /// 22 | public const int RealSymmetricIndefinite = -2; 23 | 24 | /// 25 | /// Complex and structurally symmetric matrix. 26 | /// 27 | public const int ComplexStructurallySymmetric = 3; 28 | 29 | /// 30 | /// Complex and Hermitian positive definite matrix. 31 | /// 32 | public const int ComplexHermitianPositiveDefinite = 4; 33 | 34 | /// 35 | /// Complex and Hermitian indefinite matrix. 36 | /// 37 | public const int ComplexHermitianIndefinite = -4; 38 | 39 | /// 40 | /// Complex and symmetric matrix. 41 | /// 42 | public const int ComplexSymmetric = 6; 43 | 44 | /// 45 | /// Real and nonsymmetric matrix. 46 | /// 47 | public const int RealNonsymmetric = 11; 48 | 49 | /// 50 | /// Complex and nonsymmetric matrix. 51 | /// 52 | public const int ComplexNonsymmetric = 13; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/Pardiso/PardisoOrdering.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL.Pardiso 3 | { 4 | /// 5 | /// Column ordering method. 6 | /// 7 | public enum PardisoOrdering : int 8 | { 9 | /// 10 | /// Minimum degree ordering. 11 | /// 12 | MinimumDegree = 0, 13 | /// 14 | /// Nested dissection using METIS. 15 | /// 16 | NestedDissection = 2, 17 | /// 18 | /// Parallel (OpenMP) version of the nested dissection algorithm. 19 | /// 20 | ParallelNestedDissection = 3 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/MKL/Types.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.MKL 3 | { 4 | using System; 5 | using System.Runtime.InteropServices; 6 | 7 | #region Enums 8 | 9 | /// 10 | /// status of the routines 11 | /// 12 | public enum SparseStatus 13 | { 14 | /// 15 | /// the operation was successful 16 | /// 17 | Success = 0, 18 | /// 19 | /// empty handle or matrix arrays 20 | /// 21 | NotInitialized = 1, 22 | /// 23 | /// internal error: memory allocation failed 24 | /// 25 | AllocFailed = 2, 26 | /// 27 | /// invalid input value 28 | /// 29 | InvalidValue = 3, 30 | /// 31 | /// e.g. 0-diagonal element for triangular solver, etc. 32 | /// 33 | ExecutionFailed = 4, 34 | /// 35 | /// internal error 36 | /// 37 | InternalError = 5, 38 | /// 39 | /// operation for double precision doesn't support other types 40 | /// 41 | NotSupported = 6 42 | } 43 | 44 | /// 45 | /// sparse matrix operations 46 | /// 47 | enum SparseOperation 48 | { 49 | NonTranspose = 10, 50 | Transpose = 11, 51 | ConjugateTranspose = 12 52 | } 53 | 54 | /// 55 | /// supported matrix types 56 | /// 57 | enum SparseMatrixType 58 | { 59 | General = 20, 60 | Symmetric = 21, 61 | Hermitian = 22, 62 | Triangular = 23, 63 | Diagonal = 24, 64 | BlockTriangular = 25, 65 | BlockDiagonal = 26 66 | } 67 | 68 | /// 69 | /// sparse matrix indexing: C-style or Fortran-style 70 | /// 71 | enum SparseIndexBase 72 | { 73 | Zero = 0, 74 | One = 1 75 | } 76 | 77 | /// 78 | /// applies to triangular matrices only ( SYMMETRIC, HERMITIAN, TRIANGULAR ) 79 | /// 80 | enum SparseFillMode 81 | { 82 | Lower = 40, 83 | Upper = 41, 84 | Full = 42 85 | } 86 | 87 | /// 88 | /// applies to triangular matrices only ( SYMMETRIC, HERMITIAN, TRIANGULAR ) 89 | /// 90 | enum SparseDiagType 91 | { 92 | NonUnit = 50, 93 | Unit = 51 94 | } 95 | 96 | /// 97 | /// applicable for Level 3 operations with dense matrices; describes storage scheme for dense matrix (row major or column major) 98 | /// 99 | enum SparseLayout 100 | { 101 | RowMajor = 101, /* C-style */ 102 | ColumnMajor = 102 /* Fortran-style */ 103 | } 104 | 105 | 106 | enum SparseQrHint 107 | { 108 | SPARSE_QR_WITH_PIVOTS = 0 109 | } 110 | 111 | #endregion 112 | 113 | [StructLayout(LayoutKind.Sequential)] 114 | internal struct MKLVersion 115 | { 116 | public int MajorVersion; 117 | public int MinorVersion; 118 | public int BuildNumber; 119 | IntPtr ProductStatus; // char* 120 | IntPtr Build; // char* 121 | IntPtr Processor; // char* 122 | IntPtr Platform; // char* 123 | } 124 | 125 | [StructLayout(LayoutKind.Sequential)] 126 | internal struct MatrixDescriptor 127 | { 128 | public SparseMatrixType type; 129 | public SparseFillMode mode; 130 | public SparseDiagType diag; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/Metis/Helper.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Metis 3 | { 4 | static class Helper 5 | { 6 | public static int[] CreateArray(int n, int value) 7 | { 8 | var data = new int[n]; 9 | 10 | for (int i = 0; i < n; i++) 11 | { 12 | data[i] = value; 13 | } 14 | 15 | return data; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/Spectra/SpectraException.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.Spectra 2 | { 3 | using System; 4 | 5 | /// 6 | /// Spectra exception. 7 | /// 8 | public class SpectraException : Exception 9 | { 10 | public int ErrorCode { get; private set; } 11 | 12 | public SpectraException(int error) 13 | : base(GetErrorMessage(error)) 14 | { 15 | ErrorCode = error; 16 | } 17 | 18 | public static string GetErrorMessage(int error) 19 | { 20 | switch (error) 21 | { 22 | case NO_ERRORS: 23 | return string.Empty; 24 | case NOT_COMPUTED: 25 | return "Computation has not been conducted. Call compute() member function."; 26 | case NOT_CONVERGING: 27 | return "Some eigenvalues did not converge."; 28 | case NUMERICAL_ISSUE: 29 | return "Cholesky decomposition failed, the matrix is not positive definite."; 30 | case EXCEPTION_STD: 31 | return "C++ std::exception was thrown."; 32 | case INVALID_ARGUMENT: 33 | return "C++ std::invalid_argument was thrown."; 34 | case EXCEPTION_UNKNOWN: 35 | return "C++ unkown exception occurred."; 36 | default: 37 | return "There is something wrong (" + error + ")"; 38 | } 39 | } 40 | 41 | #region Error codes 42 | 43 | // Innocuous error type. 44 | 45 | private const int NO_ERRORS = 0; 46 | 47 | // Errors in parameter definitions. 48 | 49 | private const int NOT_COMPUTED = 1; 50 | private const int NOT_CONVERGING = 2; 51 | private const int NUMERICAL_ISSUE = 3; 52 | 53 | // Other severe errors. 54 | 55 | private const int EXCEPTION_STD = -1000; 56 | private const int EXCEPTION_UNKNOWN = -1001; 57 | private const int INVALID_ARGUMENT = -1002; 58 | 59 | #endregion 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/Spectra/SpectraResult.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.Spectra 3 | { 4 | using CSparse.Interop.Common; 5 | using CSparse.Solvers; 6 | using CSparse.Storage; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Numerics; 10 | using System.Runtime.InteropServices; 11 | 12 | /// 13 | /// Spectra result. 14 | /// 15 | public abstract class SpectraResult : IEigenSolverResult 16 | where T : struct, IEquatable, IFormattable 17 | { 18 | // The following objects are actually double[] arrays, which are initialized in the derived classes. 19 | // See implementation of abstract methods CreateEigenValuesArray() and CreateEigenVectorsMatrix(). 20 | // 21 | // If anyone needs single precision, those could also be float[] arrays. 22 | 23 | protected object eigvec; 24 | protected object eigval; 25 | 26 | protected int size; 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// The number of eigenvalues requested. 32 | /// The problem size. 33 | public SpectraResult(int k, int size) 34 | { 35 | this.Count = k; 36 | 37 | this.size = size; 38 | } 39 | 40 | /// 41 | public int Count { get; private set; } 42 | 43 | /// 44 | public int ConvergedEigenValues { get; internal set; } 45 | 46 | /// 47 | public int IterationsTaken { get; internal set; } 48 | 49 | /// 50 | public int ArnoldiCount { get; internal set; } 51 | 52 | /// 53 | /// Gets the error code returned by Spectra (0 = all fine). 54 | /// 55 | public int ErrorCode { get; internal set; } 56 | 57 | /// 58 | public bool HasEigenVectors => ConvergedEigenValues > 0 && eigvec != null; 59 | 60 | /// 61 | public Matrix EigenVectors 62 | { 63 | get 64 | { 65 | if (eigvec == null) 66 | { 67 | return null; 68 | } 69 | 70 | return CreateEigenVectorsMatrix(); 71 | } 72 | } 73 | 74 | /// 75 | public Complex[] EigenValues 76 | { 77 | get 78 | { 79 | if (eigval == null) 80 | { 81 | return null; 82 | } 83 | 84 | return CreateEigenValuesArray(); 85 | } 86 | } 87 | 88 | /// 89 | /// Throws an , if Spectra failed to solve the problem. 90 | /// 91 | public void EnsureSuccess() 92 | { 93 | if (ErrorCode != 0) 94 | { 95 | throw new SpectraException(ErrorCode); 96 | } 97 | } 98 | 99 | /// 100 | public abstract double[] EigenValuesReal(); 101 | 102 | /// 103 | public abstract Matrix EigenVectorsReal(); 104 | 105 | /// 106 | /// Creates the array of eigenvalues. 107 | /// 108 | protected abstract Complex[] CreateEigenValuesArray(); 109 | 110 | /// 111 | /// Creates the matrix of eigenvectors. 112 | /// 113 | protected abstract DenseColumnMajorStorage CreateEigenVectorsMatrix(); 114 | 115 | internal spectra_result GetEigenvalueStorage(List handles) 116 | { 117 | spectra_result e = default(spectra_result); 118 | 119 | e.eigval = InteropHelper.Pin(eigval, handles); 120 | e.eigvec = InteropHelper.Pin(eigvec, handles); 121 | 122 | e.info = 0; 123 | 124 | return e; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuiteSparse/Cholmod/CholmodDense.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.SuiteSparse.Cholmod 2 | { 3 | using System; 4 | 5 | #if X64 6 | using size_t = System.UInt64; 7 | #else 8 | using size_t = System.UInt32; 9 | #endif 10 | 11 | /// 12 | /// A dense matrix in column-oriented form. 13 | /// 14 | /// 15 | /// Entry in row i and column j is located in x [i+j*d] 16 | /// 17 | public struct CholmodDense 18 | { 19 | /// 20 | /// the matrix is nrow-by-ncol 21 | /// 22 | public size_t nrow; 23 | /// 24 | /// the matrix is nrow-by-ncol 25 | /// 26 | public size_t ncol; 27 | /// 28 | /// maximum number of entries in the matrix 29 | /// 30 | public size_t nzmax; 31 | /// 32 | /// leading dimension (d >= nrow must hold) 33 | /// 34 | public size_t d; 35 | /// 36 | /// size nzmax or 2*nzmax, if present 37 | /// 38 | public IntPtr x; 39 | /// 40 | /// size nzmax, if present 41 | /// 42 | public IntPtr z; 43 | /// 44 | /// pattern, real, complex, or zomplex 45 | /// 46 | public Xtype xtype; 47 | /// 48 | /// x and z double or float 49 | /// 50 | public Dtype dtype; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuiteSparse/Cholmod/CholmodException.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.SuiteSparse.Cholmod 2 | { 3 | using System; 4 | 5 | /// 6 | /// CHOLMOD exception. 7 | /// 8 | public class CholmodException : Exception 9 | { 10 | /// 11 | /// Zero means success, negative means a fatal error, positive is a warning. 12 | /// 13 | public int ErrorCode { get; private set; } 14 | 15 | public CholmodException(int error) 16 | : base(GetErrorMessage(error)) 17 | { 18 | ErrorCode = error; 19 | } 20 | 21 | public static string GetErrorMessage(int error) 22 | { 23 | switch (error) 24 | { 25 | case CHOLMOD_OK: 26 | return string.Empty; 27 | case CHOLMOD_NOT_INSTALLED: 28 | return "Failure: method not installed."; 29 | case CHOLMOD_OUT_OF_MEMORY: 30 | return "Failure: out of memory."; 31 | case CHOLMOD_TOO_LARGE: 32 | return "Failure: integer overflow occured."; 33 | case CHOLMOD_INVALID: 34 | return "Failure: invalid input."; 35 | case CHOLMOD_GPU_PROBLEM: 36 | return "Failure: GPU fatal error."; 37 | case CHOLMOD_NOT_POSDEF: 38 | return "Warning: matrix not pos. definite."; 39 | case CHOLMOD_DSMALL: 40 | return "Warning: D for LDL' or diag(L) or LL' has tiny absolute value."; 41 | default: 42 | return "There is something wrong."; 43 | } 44 | } 45 | 46 | #region Error codes 47 | 48 | private const int CHOLMOD_OK = 0; 49 | private const int CHOLMOD_NOT_INSTALLED = -1; 50 | private const int CHOLMOD_OUT_OF_MEMORY = -2; 51 | private const int CHOLMOD_TOO_LARGE = -3; 52 | private const int CHOLMOD_INVALID = -4; 53 | private const int CHOLMOD_GPU_PROBLEM = -5; 54 | private const int CHOLMOD_NOT_POSDEF = 1; 55 | private const int CHOLMOD_DSMALL = 2; 56 | 57 | #endregion 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuiteSparse/Cholmod/CholmodSparse.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.SuiteSparse.Cholmod 2 | { 3 | using System; 4 | 5 | #if X64 6 | using size_t = System.UInt64; 7 | #else 8 | using size_t = System.UInt32; 9 | #endif 10 | 11 | /// 12 | /// A sparse matrix stored in compressed-column form. 13 | /// 14 | public struct CholmodSparse 15 | { 16 | /// 17 | /// the matrix is nrow-by-ncol 18 | /// 19 | public size_t nrow; 20 | /// 21 | /// the matrix is nrow-by-ncol 22 | /// 23 | public size_t ncol; 24 | /// 25 | /// maximum number of entries in the matrix 26 | /// 27 | public size_t nzmax; 28 | 29 | /* pointers to int or SuiteSparse_long: */ 30 | /// 31 | /// p [0..ncol], the column pointers 32 | /// 33 | public IntPtr p; 34 | /// 35 | /// i [0..nzmax-1], the row indices 36 | /// 37 | public IntPtr i; 38 | 39 | /* for unpacked matrices only: */ 40 | /// 41 | /// nz [0..ncol-1], the # of nonzeros in each col. 42 | /// 43 | public IntPtr nz; 44 | 45 | /* pointers to double or float: */ 46 | /// 47 | /// size nzmax or 2*nzmax, if present 48 | /// 49 | public IntPtr x; 50 | /// 51 | /// size nzmax, if present 52 | /// 53 | public IntPtr z; 54 | 55 | /// 56 | /// Describes what parts of the matrix are considered 57 | /// 58 | public Stype stype; 59 | 60 | /// 61 | /// interger type 62 | /// 63 | public int itype; 64 | 65 | /// 66 | /// pattern, real, complex, or zomplex 67 | /// 68 | public Xtype xtype; 69 | /// 70 | /// x and z are double or float 71 | /// 72 | public Dtype dtype; 73 | /// 74 | /// TRUE if columns are sorted, FALSE otherwise 75 | /// 76 | public int sorted; 77 | /// 78 | /// TRUE if packed (nz ignored), FALSE if unpacked (nz is required) 79 | /// 80 | public int packed; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuiteSparse/SPQR/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.SuiteSparse.SPQR 2 | { 3 | internal static class Constants 4 | { 5 | // From SuiteSparseQR_definitions.h 6 | 7 | /* ordering options */ 8 | public const int SPQR_ORDERING_FIXED = 0; 9 | public const int SPQR_ORDERING_NATURAL = 1; 10 | public const int SPQR_ORDERING_COLAMD = 2; 11 | public const int SPQR_ORDERING_GIVEN = 3; /* only used for C/C++ interface */ 12 | public const int SPQR_ORDERING_CHOLMOD = 4; /* */ 13 | public const int SPQR_ORDERING_AMD = 5; /* AMD(A'*A) */ 14 | public const int SPQR_ORDERING_METIS = 6; /* metis(A'*A) */ 15 | public const int SPQR_ORDERING_DEFAULT = 7; /* SuiteSparseQR default ordering */ 16 | public const int SPQR_ORDERING_BEST = 8; /* try COLAMD, AMD, and METIS; pick best */ 17 | public const int SPQR_ORDERING_BESTAMD = 9; /* try COLAMD and AMD; pick best */ 18 | 19 | /* Let [m n] = size of the matrix after pruning singletons. The default 20 | * ordering strategy is to use COLAMD if m <= 2*n. Otherwise, AMD(A'A) is 21 | * tried. If there is a high fill-in with AMD then try METIS(A'A) and take 22 | * the best of AMD and METIS. METIS is not tried if it isn't installed. */ 23 | 24 | /* tol options */ 25 | public const int SPQR_DEFAULT_TOL = -2; /* if tol <= -2, the default tol is used */ 26 | public const int SPQR_NO_TOL = -1; /* if -2 < tol < 0, then no tol is used */ 27 | 28 | /* for qmult, method can be 0,1,2,3: */ 29 | public const int SPQR_QTX = 0; 30 | public const int SPQR_QX = 1; 31 | public const int SPQR_XQT = 2; 32 | public const int SPQR_XQ = 3; 33 | 34 | /* system can be 0,1,2,3: Given Q*R=A*E from SuiteSparseQR_factorize: */ 35 | public const int SPQR_RX_EQUALS_B = 0; /* solve R*X=B or X = R\B */ 36 | public const int SPQR_RETX_EQUALS_B = 1; /* solve R*E'*X=B or X = E*(R\B) */ 37 | public const int SPQR_RTX_EQUALS_B = 2; /* solve R'*X=B or X = R'\B */ 38 | public const int SPQR_RTX_EQUALS_ETB = 3; /* solve R'*X=E'*B or X = R'\(E'*B) */ 39 | 40 | public const int CHOLMOD_OK = 0; /* success */ 41 | public const int TRUE = 1; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuiteSparse/SPQR/SpqrOrdering.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.SuiteSparse.SPQR 3 | { 4 | /// 5 | /// Ordering method to use. 6 | /// 7 | public enum SpqrOrdering : int 8 | { 9 | /// 10 | /// Fixed ordering. 11 | /// 12 | Fixed = Constants.SPQR_ORDERING_FIXED, 13 | /// 14 | /// Use natural ordering. 15 | /// 16 | Natural = Constants.SPQR_ORDERING_NATURAL, 17 | /// 18 | /// Use COLAMD. 19 | /// 20 | COLAMD = Constants.SPQR_ORDERING_COLAMD, 21 | /// 22 | /// Use given permutation. 23 | /// 24 | Given = Constants.SPQR_ORDERING_GIVEN, 25 | /// 26 | /// Use CHOLMOD best-effort (COLAMD, METIS, ...). 27 | /// 28 | CHOLMOD = Constants.SPQR_ORDERING_CHOLMOD, 29 | /// 30 | /// Use minimum degree AMD(A'*A). 31 | /// 32 | AMD = Constants.SPQR_ORDERING_AMD, 33 | /// 34 | /// Use METIS(A'*A) nested dissection. 35 | /// 36 | METIS = Constants.SPQR_ORDERING_METIS, 37 | /// 38 | /// Use SuiteSparseQR default ordering. 39 | /// 40 | Default = Constants.SPQR_ORDERING_DEFAULT, 41 | /// 42 | /// Try COLAMD/AMD/METIS and use best. 43 | /// 44 | Best = Constants.SPQR_ORDERING_BEST, 45 | /// 46 | /// Try COLAMD/AMD and use best. 47 | /// 48 | BestAMD = Constants.SPQR_ORDERING_BESTAMD 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuiteSparse/Umfpack/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.SuiteSparse.Umfpack 2 | { 3 | internal static class Constants 4 | { 5 | public const int UMFPACK_OK = 0; 6 | 7 | public const int UMFPACK_INFO = 90; 8 | public const int UMFPACK_CONTROL = 20; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuiteSparse/Umfpack/UmfpackException.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.SuiteSparse.Umfpack 2 | { 3 | using System; 4 | 5 | /// 6 | /// UMFPACK exception. 7 | /// 8 | public class UmfpackException : Exception 9 | { 10 | /// 11 | /// Zero means success, negative means a fatal error, positive is a warning. 12 | /// 13 | public int ErrorCode { get; private set; } 14 | 15 | public UmfpackException(int error) 16 | : base(GetErrorMessage(error)) 17 | { 18 | ErrorCode = error; 19 | } 20 | 21 | public static string GetErrorMessage(int error) 22 | { 23 | switch (error) 24 | { 25 | case UMFPACK_OK: 26 | return string.Empty; 27 | case UMFPACK_WARNING_singular_matrix: 28 | return "WARNING: matrix is singular"; 29 | case UMFPACK_ERROR_out_of_memory: 30 | return "ERROR: out of memory"; 31 | case UMFPACK_ERROR_invalid_Numeric_object: 32 | return "ERROR: Numeric object is invalid"; 33 | case UMFPACK_ERROR_invalid_Symbolic_object: 34 | return "ERROR: Symbolic object is invalid"; 35 | case UMFPACK_ERROR_argument_missing: 36 | return "ERROR: required argument(s) missing"; 37 | case UMFPACK_ERROR_n_nonpositive: 38 | return "ERROR: dimension (n_row or n_col) must be > 0"; 39 | case UMFPACK_ERROR_invalid_matrix: 40 | return "ERROR: input matrix is invalid"; 41 | case UMFPACK_ERROR_invalid_system: 42 | return "ERROR: system argument invalid"; 43 | case UMFPACK_ERROR_invalid_permutation: 44 | return "ERROR: invalid permutation"; 45 | case UMFPACK_ERROR_different_pattern: 46 | return "ERROR: pattern of matrix (Ap and/or Ai) has changed"; 47 | case UMFPACK_ERROR_ordering_failed: 48 | return "ERROR: ordering failed"; 49 | case UMFPACK_ERROR_internal_error: 50 | return "INTERNAL ERROR! Input arguments might be corrupted or aliased, or an internal error has occurred."; 51 | default: 52 | return "ERROR: Unrecognized error code: " + error; 53 | } 54 | } 55 | 56 | #region Error codes 57 | 58 | // status codes (see umfpack.h) 59 | 60 | private const int UMFPACK_OK = 0; 61 | 62 | /* status > 0 means a warning, but the method was successful anyway. */ 63 | /* A Symbolic or Numeric object was still created. */ 64 | private const int UMFPACK_WARNING_singular_matrix = 1; 65 | 66 | /* The following warnings were added in umfpack_*_get_determinant */ 67 | private const int UMFPACK_WARNING_determinant_underflow = 2; 68 | private const int UMFPACK_WARNING_determinant_overflow = 3; 69 | 70 | /* status < 0 means an error, and the method was not successful. */ 71 | /* No Symbolic of Numeric object was created. */ 72 | private const int UMFPACK_ERROR_out_of_memory = -1; 73 | private const int UMFPACK_ERROR_invalid_Numeric_object = -3; 74 | private const int UMFPACK_ERROR_invalid_Symbolic_object = -4; 75 | private const int UMFPACK_ERROR_argument_missing = -5; 76 | private const int UMFPACK_ERROR_n_nonpositive = -6; 77 | private const int UMFPACK_ERROR_invalid_matrix = -8; 78 | private const int UMFPACK_ERROR_different_pattern = -11; 79 | private const int UMFPACK_ERROR_invalid_system = -13; 80 | private const int UMFPACK_ERROR_invalid_permutation = -15; 81 | private const int UMFPACK_ERROR_internal_error = -911; /* yes, call me if you get this! */ 82 | private const int UMFPACK_ERROR_file_IO = -17; 83 | 84 | private const int UMFPACK_ERROR_ordering_failed = -18; 85 | 86 | #endregion 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuiteSparse/Umfpack/UmfpackSolve.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.SuiteSparse.Umfpack 3 | { 4 | /// 5 | /// Umfpack solve codes. 6 | /// 7 | /// 8 | /// Solve the system ( )x=b, where ( ) is defined below. "t" refers to the 9 | /// linear algebraic transpose (complex conjugate if A is complex), or the (') 10 | /// operator in MATLAB. "at" refers to the array transpose, or the (.') 11 | /// operator in MATLAB. 12 | /// 13 | public enum UmfpackSolve 14 | { 15 | /// 16 | /// Ax=b 17 | /// 18 | A = 0, 19 | /// 20 | /// A'x=b 21 | /// 22 | At = 1, 23 | /// 24 | /// A.'x=b 25 | /// 26 | Aat = 2, 27 | 28 | /// 29 | /// P'Lx=b 30 | /// 31 | Pt_L = 3, 32 | /// 33 | /// Lx=b 34 | /// 35 | L = 4, 36 | /// 37 | /// L'Px=b 38 | /// 39 | Lt_P = 5, 40 | /// 41 | /// L.'Px=b 42 | /// 43 | Lat_P = 6, 44 | /// 45 | /// L'x=b 46 | /// 47 | Lt = 7, 48 | /// 49 | /// L.'x=b 50 | /// 51 | Lat = 8, 52 | 53 | /// 54 | /// UQ'x=b 55 | /// 56 | U_Qt = 9, 57 | /// 58 | /// Ux=b 59 | /// 60 | U = 10, 61 | /// 62 | /// QU'x=b 63 | /// 64 | Q_Ut = 11, 65 | /// 66 | /// QU.'x=b 67 | /// 68 | Q_Uat = 12, 69 | /// 70 | /// U'x=b 71 | /// 72 | Ut = 13, 73 | /// 74 | /// U.'x=b 75 | /// 76 | Uat = 14 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuperLU/Constants.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.SuperLU 3 | { 4 | public enum UpdateLevel 5 | { 6 | SamePattern = 2, 7 | SamePatternSameRowPerm = 3 8 | } 9 | 10 | internal class Constants 11 | { 12 | internal const int DOFACT = 0; 13 | internal const int EQUILIBRATE = 1; 14 | internal const int FACTORED_MT = 2; 15 | internal const int FACTORED = 3; 16 | 17 | // Dropping rules 18 | internal const int NODROP = (0x0000); 19 | internal const int DROP_BASIC = (0x0001); // ILU(tau) 20 | internal const int DROP_PROWS = (0x0002); // ILUTP: keep p maximum rows 21 | internal const int DROP_COLUMN = (0x0004); // ILUTP: for j-th column, p = gamma * nnz(A(:,j)) 22 | internal const int DROP_AREA = (0x0008); // ILUTP: for j-th column, use nnz(F(:,1:j)) / nnz(A(:,1:j)) to limit memory growth 23 | internal const int DROP_SECONDARY = (0x000E); // PROWS | COLUMN | AREA 24 | internal const int DROP_DYNAMIC = (0x0010); // adaptive tau 25 | internal const int DROP_INTERP = (0x0100); // use interpolation 26 | 27 | /* 28 | enum fact_mt_t { DOFACT, EQUILIBRATE, FACTORED }; 29 | 30 | internal enum fact_t { DOFACT, SamePattern, SamePattern_SameRowPerm, FACTORED }; 31 | internal enum rowperm_t { NOROWPERM, LargeDiag, MY_PERMR }; 32 | internal enum colperm_t 33 | { 34 | NATURAL, MMD_ATA, MMD_AT_PLUS_A, COLAMD, 35 | METIS_AT_PLUS_A, PARMETIS, ZOLTAN, MY_PERMC 36 | }; 37 | internal enum trans_t { NOTRANS, TRANS, CONJ }; 38 | internal enum DiagScale_t { NOEQUIL, ROW, COL, BOTH }; 39 | internal enum IterRefine_t { NOREFINE, SLU_SINGLE = 1, SLU_DOUBLE, SLU_EXTRA }; 40 | internal enum norm_t { ONE_NORM, TWO_NORM, INF_NORM }; 41 | internal enum milu_t { SILU, SMILU_1, SMILU_2, SMILU_3 }; 42 | //*/ 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuperLU/OrderingMethod.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Interop.SuperLU 2 | { 3 | /// 4 | /// Column ordering method. 5 | /// 6 | public enum OrderingMethod 7 | { 8 | /// 9 | /// Natural ordering. 10 | /// 11 | Natural, 12 | /// 13 | /// Minimum degree ordering on the structure of A^TA. 14 | /// 15 | MinimumDegreeAtA, 16 | /// 17 | /// Minimum degree ordering on the structure of A^T+A. 18 | /// 19 | MinimumDegreeAtPlusA, 20 | /// 21 | /// Column approximate minimum degree ordering. 22 | /// 23 | ColumnApproximateMinimumDegree 24 | /* 25 | /// 26 | /// ??? 27 | /// 28 | MetisAtPlusA, 29 | /// 30 | /// ??? 31 | /// 32 | ParMetis, 33 | /// 34 | /// ??? 35 | /// 36 | ZOLTAN, 37 | /// 38 | /// Custom permutation (stored in perm_c array). 39 | /// 40 | Custom 41 | //*/ 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /CSparse.Interop/Interop/SuperLU/SuperLUException.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Interop.SuperLU 3 | { 4 | using System; 5 | 6 | public class SuperLUException : Exception 7 | { 8 | private const string ErrorArgument = "Argument at position {0} had an illegal value."; 9 | private const string ErrorConditon = "U is nonsingular, but RCOND is less than machine precision, meaning that the matrix is singular to working precision."; 10 | private const string ErrorMemory = "Memory allocation failure occurred."; 11 | private const string ErrorSingular = "The factorization has been completed, but the factor U is singular at position {0}."; 12 | 13 | public int ErrorCode { get; private set; } 14 | 15 | public SuperLUException(int code, int ncol) 16 | : base(GetErrorMessage(code, ncol)) 17 | { 18 | this.ErrorCode = code; 19 | } 20 | 21 | private static string GetErrorMessage(int code, int ncol) 22 | { 23 | if (code < 0) 24 | { 25 | return string.Format(ErrorArgument, code); 26 | } 27 | 28 | if (code < ncol) 29 | { 30 | return string.Format(ErrorSingular, code); 31 | } 32 | 33 | if (code == ncol) 34 | { 35 | return string.Format(ErrorConditon, code); 36 | } 37 | 38 | return string.Format(ErrorMemory, code); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CSparse.Interop/Solvers/IEigenSolver.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Solvers 3 | { 4 | using System; 5 | 6 | /// 7 | /// Interface for eigensolvers. 8 | /// 9 | /// 10 | public interface IEigenSolver 11 | where T : struct, IEquatable, IFormattable 12 | { 13 | /// 14 | /// Solve the standard eigenvalue problem. 15 | /// 16 | /// The number of eigenvalues to compute. 17 | /// The part of the spectrum to compute. 18 | /// Returns an . 19 | IEigenSolverResult SolveStandard(int k, Spectrum job); 20 | 21 | /// 22 | /// Solve the standard eigenvalue problem in shift-invert mode. 23 | /// 24 | /// The number of eigenvalues to compute. 25 | /// The shift value. 26 | /// The part of the spectrum to compute. 27 | /// Returns an . 28 | IEigenSolverResult SolveStandard(int k, T sigma, Spectrum job); 29 | 30 | /// 31 | /// Solve the generalized eigenvalue problem. 32 | /// 33 | /// The number of eigenvalues to compute. 34 | /// The part of the spectrum to compute. 35 | /// Returns an . 36 | IEigenSolverResult SolveGeneralized(int k, Spectrum job); 37 | 38 | /// 39 | /// Solve the generalized eigenvalue problem in shift-invert mode. 40 | /// 41 | /// The number of eigenvalues to compute. 42 | /// The shift value. 43 | /// The part of the spectrum to compute. 44 | /// Returns an . 45 | IEigenSolverResult SolveGeneralized(int k, T sigma, Spectrum job); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /CSparse.Interop/Solvers/IEigenSolverResult.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Solvers 3 | { 4 | using System.Numerics; 5 | 6 | /// 7 | /// Interface for result returned by an . 8 | /// 9 | public interface IEigenSolverResult 10 | { 11 | /// 12 | /// Gets the number of requested eigenvalues. 13 | /// 14 | int Count { get; } 15 | 16 | /// 17 | /// Gets the number of converged eigenvalues. 18 | /// 19 | int ConvergedEigenValues { get; } 20 | 21 | /// 22 | /// Gets the number of iterations taken. 23 | /// 24 | int IterationsTaken { get; } 25 | 26 | /// 27 | /// Gets the number of Arnoldi vectors computed. 28 | /// 29 | int ArnoldiCount { get; } 30 | 31 | /// 32 | /// Gets the error code returned by the solver. 33 | /// 34 | int ErrorCode { get; } 35 | 36 | /// 37 | /// Throws an exception, if the eigensolver failed to solve the problem. 38 | /// 39 | void EnsureSuccess(); 40 | 41 | /// 42 | /// Gets a value indicating whether eigenvectors are available. 43 | /// 44 | bool HasEigenVectors { get; } 45 | 46 | /// 47 | /// Gets the dense matrix of eigenvectors stored in column major order. 48 | /// 49 | /// 50 | /// For symmetric (Hermitian) matrices, eigenvectors will be real. Use . 51 | /// 52 | Matrix EigenVectors { get; } 53 | 54 | /// 55 | /// Gets the eigenvalues. 56 | /// 57 | /// 58 | /// For symmetric (Hermitian) matrices, eigenvalues will be real. Use . 59 | /// 60 | Complex[] EigenValues { get; } 61 | 62 | /// 63 | /// Gets the real part of the eigenvalues. 64 | /// 65 | double[] EigenValuesReal(); 66 | 67 | /// 68 | /// Gets the real part of the eigenvectors. 69 | /// 70 | Matrix EigenVectorsReal(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /CSparse.Interop/Solvers/Job.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Solvers 3 | { 4 | static class Job 5 | { 6 | internal static bool Validate(bool symmetric, Spectrum job) 7 | { 8 | return symmetric ? ValidateSymmetric(job) : ValidateGeneral(job); 9 | } 10 | 11 | internal static bool ValidateSymmetric(Spectrum job) 12 | { 13 | return job == Spectrum.LargestMagnitude 14 | || job == Spectrum.LargestAlgebraic 15 | || job == Spectrum.SmallestMagnitude 16 | || job == Spectrum.SmallestAlgebraic 17 | || job == Spectrum.BothEnds; 18 | } 19 | 20 | internal static bool ValidateGeneral(Spectrum job) 21 | { 22 | return job == Spectrum.LargestMagnitude 23 | || job == Spectrum.LargestRealPart 24 | || job == Spectrum.LargestImaginaryPart 25 | || job == Spectrum.SmallestMagnitude 26 | || job == Spectrum.LargestRealPart 27 | || job == Spectrum.SmallestImaginaryPart; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CSparse.Interop/Solvers/ShiftMode.cs: -------------------------------------------------------------------------------- 1 | namespace CSparse.Solvers 2 | { 3 | public enum ShiftMode 4 | { 5 | /// 6 | /// No shift applied. 7 | /// 8 | None, 9 | /// 10 | /// Regular shift-invert mode. 11 | /// 12 | Regular, 13 | /// 14 | /// Buckling mode. 15 | /// 16 | Buckling, 17 | /// 18 | /// Cayley mode. 19 | /// 20 | Cayley 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CSparse.Interop/Solvers/Spectrum.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace CSparse.Solvers 3 | { 4 | /// 5 | /// Selection rule for the spectrum to compute. 6 | /// 7 | public enum Spectrum 8 | { 9 | /// 10 | /// Largest algebraic (ARPACK which "LA"). 11 | /// 12 | LargestAlgebraic, 13 | /// 14 | /// Largest magnitude (ARPACK which "LM"). 15 | /// 16 | LargestMagnitude, 17 | /// 18 | /// Largest real part (ARPACK which "LR"). 19 | /// 20 | LargestRealPart, 21 | /// 22 | /// Largest imaginary part (ARPACK which "LI"). 23 | /// 24 | LargestImaginaryPart, 25 | /// 26 | /// Smallest algebraic (ARPACK which "SA"). 27 | /// 28 | SmallestAlgebraic, 29 | /// 30 | /// Smallest magnitude (ARPACK which "SM"). 31 | /// 32 | SmallestMagnitude, 33 | /// 34 | /// Smallest real part (ARPACK which "SR"). 35 | /// 36 | SmallestRealPart, 37 | /// 38 | /// Smallest imaginary part (ARPACK which "SI"). 39 | /// 40 | SmallestImaginaryPart, 41 | /// 42 | /// Both ends of the spectrum (ARPACK which "BE"). 43 | /// 44 | BothEnds, 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CSparse.Interop/Storage/CompressedRowStorage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CSparse.Storage 4 | { 5 | public class CompressedRowStorage : ILinearOperator where T : struct, IEquatable, IFormattable 6 | { 7 | /// The number of rows. 8 | protected readonly int rows; 9 | 10 | /// The number of columns. 11 | protected readonly int columns; 12 | 13 | /// 14 | public int RowCount => rows; 15 | 16 | /// 17 | public int ColumnCount => columns; 18 | 19 | /// 20 | /// Gets the number of non-zero entries. 21 | /// 22 | public int NonZerosCount => RowPointers[rows]; 23 | 24 | /// 25 | /// Row pointers with last entry equal number of non-zeros (size = RowCount + 1) 26 | /// 27 | public int[] RowPointers; 28 | 29 | /// 30 | /// Column indices (size >= NonZerosCount) 31 | /// 32 | public int[] ColumnIndices; 33 | 34 | /// 35 | /// Numerical values (size >= NonZerosCount) 36 | /// 37 | public T[] Values; 38 | 39 | /// 40 | /// Initializes a new instance of the class. 41 | /// 42 | public CompressedRowStorage(CompressedColumnStorage other) 43 | { 44 | rows = other.RowCount; 45 | columns = other.ColumnCount; 46 | 47 | var A = other.Transpose(); 48 | 49 | RowPointers = A.ColumnPointers; 50 | ColumnIndices = A.RowIndices; 51 | Values = A.Values; 52 | } 53 | 54 | /// 55 | public void Multiply(T[] x, T[] y) => Multiply(x.AsSpan(), y.AsSpan()); 56 | 57 | /// 58 | public void Multiply(ReadOnlySpan x, Span y) 59 | { 60 | throw new NotImplementedException(); 61 | } 62 | 63 | /// 64 | public void Multiply(T alpha, T[] x, T beta, T[] y) => Multiply(alpha, x.AsSpan(), beta, y.AsSpan()); 65 | 66 | /// 67 | public void Multiply(T alpha, ReadOnlySpan x, T beta, Span y) 68 | { 69 | throw new NotImplementedException(); 70 | } 71 | 72 | /// 73 | public void TransposeMultiply(T[] x, T[] y) => TransposeMultiply(x.AsSpan(), y.AsSpan()); 74 | 75 | /// 76 | public void TransposeMultiply(ReadOnlySpan x, Span y) 77 | { 78 | throw new NotImplementedException(); 79 | } 80 | 81 | /// 82 | public void TransposeMultiply(T alpha, T[] x, T beta, T[] y) => TransposeMultiply(alpha, x.AsSpan(), beta, y.AsSpan()); 83 | 84 | /// 85 | public void TransposeMultiply(T alpha, ReadOnlySpan x, T beta, Span y) 86 | { 87 | throw new NotImplementedException(); 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Christian Woltering 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSparse.Interop 2 | 3 | This project contains bindings for some popular solvers of sparse linear systems. It is supposed to be an extension to [CSparse.NET](https://github.com/wo80/CSparse.NET). 4 | 5 | ## Content 6 | 7 | | Name | Type | | Version | Test (x64) | 8 | |----------:|-----:|---------:|:-------:|:----------:| 9 | | AMD | Ordering | [SuiteSparse](https://github.com/DrTimothyAldenDavis/SuiteSparse) | 7.6.0 | OK | 10 | | CHOLMOD | Direct solver | [SuiteSparse](https://github.com/DrTimothyAldenDavis/SuiteSparse) | 7.6.0 | OK | 11 | | CXSparse | Direct solver | [SuiteSparse](https://github.com/DrTimothyAldenDavis/SuiteSparse) | 7.6.0 | OK | 12 | | UMFPACK | Direct solver | [SuiteSparse](https://github.com/DrTimothyAldenDavis/SuiteSparse) | 7.6.0 | OK | 13 | | SPQR | Direct solver | [SuiteSparse](https://github.com/DrTimothyAldenDavis/SuiteSparse) | 7.6.0 | OK | 14 | | METIS | Graph partitioning | [METIS](https://github.com/KarypisLab/METIS) | 5.2.1 | OK | 15 | | SuperLU | Direct solver | [SuperLU](https://github.com/xiaoyeli/superlu) | 6.0.1 | OK | 16 | | PARDISO | Direct solver | [oneAPI MKL](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2024-0/onemkl-pardiso-parallel-direct-sparse-solver-iface.html) | 2024.0 | OK | 17 | | FEAST | Eigenvalues | [oneAPI MKL](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2024-0/extended-eigensolver-predefined-interfaces.html) | 2024.0 | OK | 18 | | Extended Eigensolver | Eigenvalues | [oneAPI MKL](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2024-0/ext-eigensolve-ifaces-find-large-small-eigenvalues.html) | 2024.0 | OK | 19 | | ARPACK | Eigenvalues | [arpack-ng](https://github.com/opencollab/arpack-ng) | 3.9.1 | OK | 20 | | Spectra | Eigenvalues | [Spectra](https://github.com/yixuan/spectra) | 1.0.1 | OK | 21 | 22 | View [test results](https://github.com/wo80/csparse-interop/wiki/Test-Results) in the wiki. 23 | 24 | ## Related projects 25 | 26 | * [vs-suitesparse](https://github.com/wo80/vs-suitesparse/) - Visual Studio solution to build SuiteSparse. 27 | * [vs-arpack](https://github.com/wo80/vs-arpack/) - Visual Studio solution to build ARPACK. 28 | * [vs-spectra](https://github.com/wo80/vs-spectra/) - Visual Studio solution to build Spectra. 29 | 30 | Pre-compiled binaries for windows users can be found [here](http://wo80.bplaced.net/packages/#tag:math). 31 | 32 | ## Dependencies 33 | 34 | MKL solvers depend on the corresponding runtime to be present. Read more about those [dependencies](https://github.com/wo80/csparse-interop/wiki/Dependencies) in the wiki. 35 | --------------------------------------------------------------------------------