direct_lu_accelerate.cpp direct_lu.hpp algorithm cstdlib vector Accelerate/Accelerate.h serif::solver::preconditioner::backend::mfem::detail::DirectLUPattern::State serif::solver::preconditioner::backend::mfem::detail::DirectLU::State serif serif::solver serif::solver::preconditioner serif::solver::preconditioner::backend serif::solver::preconditioner::backend::mfem serif::solver::preconditioner::backend::mfem::detail //sparse_direct=accelerate.CompiledasC++20initsownstaticlibrary:Accelerate'sheadersarenotvalidC++26. #include"direct_lu.hpp" #include<algorithm> #include<cstdlib> #include<vector> #include<Accelerate/Accelerate.h> namespaceserif::solver::preconditioner::backend::mfem::detail { structDirectLUPattern::State { intsize{0}; std::vector<long>column_starts; std::vector<int>row_indices; SparseOpaqueSymbolicFactorizationsymbolic{}; }; structDirectLU::State { std::shared_ptr<constDirectLUPattern>pattern; std::vector<double>values; SparseOpaqueFactorization_Doublefactor{}; mutablestd::vector<double>right; }; namespace { [[nodiscard]]SparseMatrixStructurestructure(constDirectLUPattern::State&pattern) { SparseAttributes_tattributes{}; attributes.kind=SparseOrdinary; SparseMatrixStructureresult{}; result.rowCount=pattern.size; result.columnCount=pattern.size; //Acceleratereadsbutdoesnotmodifythestructurearrays. result.columnStarts=const_cast<long*>(pattern.column_starts.data()); result.rowIndices=const_cast<int*>(pattern.row_indices.data()); result.attributes=attributes; result.blockSize=1; returnresult; } }//namespace constchar*direct_lu_backend()noexcept{return"accelerate";} booldirect_lu_available()noexcept { if(__builtin_available(macOS15.5,*)){returntrue;} returnfalse; } std::shared_ptr<constDirectLUPattern>DirectLUPattern::analyze(constintsize,constlong*column_starts,constint*row_indices,constdouble*,int&status) { if(!direct_lu_available()) { status=-1; returnnullptr; } autostate=std::make_unique<State>(); state->size=size; state->column_starts.assign(column_starts,column_starts+size+1); state->row_indices.assign(row_indices,row_indices+column_starts[size]); //Nested-dissectionordering:onthebenchmarkpotentialblock(16krows,3.4Mnonzeros)ithalvesthe //factorizationfootprint(271vs540MB)andfactorsfaster(0.25vs0.37s)thanthedefaultordering. SparseSymbolicFactorOptionssymbolic{}; symbolic.control=SparseDefaultControl; symbolic.orderMethod=SparseOrderMetis; symbolic.malloc=std::malloc; symbolic.free=std::free; if(__builtin_available(macOS15.5,*)) { state->symbolic=SparseFactor(SparseFactorizationLU,structure(*state),symbolic); } status=static_cast<int>(state->symbolic.status); if(state->symbolic.status!=SparseStatusOK) { SparseCleanup(state->symbolic); returnnullptr; } returnstd::shared_ptr<constDirectLUPattern>(newDirectLUPattern(std::move(state))); } DirectLUPattern::DirectLUPattern(std::unique_ptr<State>state):m_state(std::move(state)){} //Numericfactorizationsholdtheirownreferencetothesymbolicfactorization. DirectLUPattern::~DirectLUPattern() { if(m_state){SparseCleanup(m_state->symbolic);} } boolDirectLUPattern::matches(constintsize,constlong*column_starts,constint*row_indices)const { returnsize==m_state->size&&std::equal(m_state->column_starts.begin(),m_state->column_starts.end(),column_starts)&& std::equal(m_state->row_indices.begin(),m_state->row_indices.end(),row_indices); } std::unique_ptr<DirectLU>DirectLU::factor(std::shared_ptr<constDirectLUPattern>pattern,constdouble*values,int&status) { constauto&shape=*pattern->m_state; autostate=std::make_unique<State>(); state->values.assign(values,values+shape.column_starts[static_cast<std::size_t>(shape.size)]); state->right.resize(static_cast<std::size_t>(shape.size)); SparseMatrix_Doublematrix{}; matrix.structure=structure(shape); matrix.data=state->values.data(); SparseNumericFactorOptionsnumeric{}; numeric.control=SparseDefaultControl; numeric.scalingMethod=SparseScalingDefault; numeric.pivotTolerance=0.01; numeric.zeroTolerance=0.0; state->factor=SparseFactor(shape.symbolic,matrix,numeric); status=static_cast<int>(state->factor.status); if(state->factor.status!=SparseStatusOK) { SparseCleanup(state->factor); returnnullptr; } state->pattern=std::move(pattern); returnstd::unique_ptr<DirectLU>(newDirectLU(std::move(state))); } DirectLU::~DirectLU() { if(m_state){SparseCleanup(m_state->factor);} } voidDirectLU::solve(constdouble*right,double*solution)const { constintsize=m_state->pattern->m_state->size; std::copy(right,right+size,m_state->right.begin()); DenseVector_Doubleb{}; b.count=size; b.data=m_state->right.data(); DenseVector_Doublex{}; x.count=size; x.data=solution; SparseSolve(m_state->factor,b,x); } voidDirectLU::solve_many(constintcount,constdouble*right,double*solution)const { constintsize=m_state->pattern->m_state->size; std::vector<double>copy(right,right+static_cast<std::size_t>(size)*static_cast<std::size_t>(count)); DenseMatrix_Doubleb{}; b.rowCount=size; b.columnCount=count; b.columnStride=size; b.data=copy.data(); DenseMatrix_Doublex=b; x.data=solution; SparseSolve(m_state->factor,b,x); } DirectLU::DirectLU(std::unique_ptr<State>state):m_state(std::move(state)){} }//namespaceserif::solver::preconditioner::backend::mfem::detail