diff --git a/libs/_cxx20/math_algos.h b/libs/_cxx20/math_algos.h index 90c07a4e8efd1d6f7efb1ae982a30004d65b8271..55d3877030e7131c14c53b3482968c2eb274dcbb 100644 --- a/libs/_cxx20/math_algos.h +++ b/libs/_cxx20/math_algos.h @@ -366,7 +366,8 @@ requires is_complex<T> */ template<class t_vec> bool equals(const t_vec& vec1, const t_vec& vec2, - typename t_vec::value_type eps = std::numeric_limits<typename t_vec::value_type>::epsilon()) + typename t_vec::value_type eps = std::numeric_limits<typename t_vec::value_type>::epsilon(), + int _maxSize = -1) requires is_basic_vec<t_vec> { using T = typename t_vec::value_type; @@ -375,8 +376,12 @@ requires is_basic_vec<t_vec> if(vec1.size() != vec2.size()) return false; + std::size_t maxSize = vec1.size(); + if(_maxSize >= 0) + maxSize = std::min(std::size_t(_maxSize), maxSize); + // check each element - for(std::size_t i=0; i<vec1.size(); ++i) + for(std::size_t i=0; i<maxSize; ++i) { if constexpr(is_complex<decltype(eps)>) { @@ -398,7 +403,8 @@ requires is_basic_vec<t_vec> */ template<class t_mat> bool equals(const t_mat& mat1, const t_mat& mat2, - typename t_mat::value_type eps = std::numeric_limits<typename t_mat::value_type>::epsilon()) + typename t_mat::value_type eps = std::numeric_limits<typename t_mat::value_type>::epsilon(), + int _maxSize = -1) requires is_mat<t_mat> { using T = typename t_mat::value_type; @@ -406,9 +412,17 @@ requires is_mat<t_mat> if(mat1.size1() != mat2.size1() || mat1.size2() != mat2.size2()) return false; - for(std::size_t i=0; i<mat1.size1(); ++i) + std::size_t maxSize1 = mat1.size1(); + std::size_t maxSize2 = mat1.size2(); + if(_maxSize >= 0) { - for(std::size_t j=0; j<mat1.size2(); ++j) + maxSize1 = std::min(std::size_t(_maxSize), maxSize1); + maxSize2 = std::min(std::size_t(_maxSize), maxSize2); + } + + for(std::size_t i=0; i<maxSize1; ++i) + { + for(std::size_t j=0; j<maxSize2; ++j) { if(!equals<T>(mat1(i,j), mat2(i,j), eps)) return false; @@ -424,7 +438,8 @@ requires is_mat<t_mat> */ template<class t_obj, template<class...> class t_vec=std::vector> bool equals_all(const t_vec<t_obj>& vec1, const t_vec<t_obj>& _vec2, - typename t_obj::value_type eps = std::numeric_limits<typename t_obj::value_type>::epsilon()) + typename t_obj::value_type eps = std::numeric_limits<typename t_obj::value_type>::epsilon(), + int maxSize=-1) { auto vec2 = _vec2; if(vec1.size() != vec2.size()) @@ -433,9 +448,10 @@ bool equals_all(const t_vec<t_obj>& vec1, const t_vec<t_obj>& _vec2, for(const auto& obj1 : vec1) { // find obj1 in vec2 - auto iter = std::find_if(vec2.crbegin(), vec2.crend(), [&obj1, eps](const t_obj& obj2) -> bool + auto iter = std::find_if(vec2.crbegin(), vec2.crend(), + [&obj1, eps, maxSize](const t_obj& obj2) -> bool { - return m::equals<t_obj>(obj1, obj2, eps); + return m::equals<t_obj>(obj1, obj2, eps, maxSize); }); // not found @@ -450,6 +466,32 @@ bool equals_all(const t_vec<t_obj>& vec1, const t_vec<t_obj>& _vec2, } +/** + * remove duplicate vectors or matrices in the container + */ +template<class t_obj, template<class...> class t_cont = std::vector> +t_cont<t_obj> remove_duplicates(const t_cont<t_obj>& objs, + typename t_obj::value_type eps = std::numeric_limits<typename t_obj::value_type>::epsilon()) +{ + t_cont<t_obj> newobjs = objs; + + for(const auto& elem : objs) + { + // find obj in container + auto iter = std::find_if(newobjs.cbegin(), newobjs.cend(), + [&elem, eps](const t_obj& elem2) -> bool + { + return m::equals<t_obj>(elem, elem2, eps); + }); + + // not found + if(iter == newobjs.cend()) + newobjs.push_back(elem); + } + + return newobjs; +} + /** * set submatrix to unit @@ -3911,11 +3953,53 @@ requires is_basic_vec<t_vec> +/** + * wrap atom positions back to unit cell + */ +template<class t_vec, class t_real = typename t_vec::value_type> +t_vec keep_atom_in_uc(const t_vec& _atom) +requires is_vec<t_vec> +{ + auto newatom = _atom; + + for(std::size_t i=0; i<newatom.size(); ++i) + { + newatom[i] = std::fmod(newatom[i], t_real{1}); + if(newatom[i] < t_real{-0.5}) + newatom[i] += std::abs(std::floor(newatom[i])); + if(newatom[i] >= t_real{0.5}) + newatom[i] -= std::abs(std::ceil(newatom[i])); + } + + return newatom; +} + + + +/** + * wrap collection of atom positions back to unit cell + */ +template<class t_vec, class t_real = typename t_vec::value_type, + template<class...> class t_cont = std::vector> +t_cont<t_vec> keep_atoms_in_uc(const t_cont<t_vec>& _atoms) +requires is_vec<t_vec> +{ + t_cont<t_vec> newatoms; + + for(const auto& _atom : _atoms) + newatoms.emplace_back(keep_atom_in_uc<t_vec, t_real>(_atom)); + + return newatoms; +} + + + /** * create positions using the given symmetry operations */ -template<class t_vec, class t_mat, class t_real = typename t_vec::value_type> -std::vector<t_vec> apply_ops_hom(const t_vec& _atom, const std::vector<t_mat>& ops, +template<class t_vec, class t_mat, class t_real = typename t_vec::value_type, + template<class...> class t_cont = std::vector> +t_cont<t_vec> apply_ops_hom(const t_vec& _atom, const t_cont<t_mat>& ops, t_real eps=std::numeric_limits<t_real>::epsilon(), bool bKeepInUnitCell=true) requires is_vec<t_vec> && is_mat<t_mat> { @@ -3924,7 +4008,7 @@ requires is_vec<t_vec> && is_mat<t_mat> if(atom.size() == 3) atom = create<t_vec>({atom[0], atom[1], atom[2], 1}); - std::vector<t_vec> newatoms; + t_cont<t_vec> newatoms; for(const auto& op : ops) { @@ -3932,16 +4016,7 @@ requires is_vec<t_vec> && is_mat<t_mat> newatom.resize(3); if(bKeepInUnitCell) - { - for(std::size_t i=0; i<newatom.size(); ++i) - { - newatom[i] = std::fmod(newatom[i], t_real{1}); - if(newatom[i] < t_real{-0.5}) - newatom[i] += std::abs(std::floor(newatom[i])); - if(newatom[i] >= t_real{0.5}) - newatom[i] -= std::abs(std::ceil(newatom[i])); - } - } + newatom = keep_atom_in_uc<t_vec>(newatom); // position already occupied? if(std::find_if(newatoms.begin(), newatoms.end(), [&newatom, eps](const t_vec& vec)->bool @@ -3955,8 +4030,6 @@ requires is_vec<t_vec> && is_mat<t_mat> return newatoms; } - - // ----------------------------------------------------------------------------