This issue comes from a Codex global scan of deepmodeling/deepmd-kit at commit 73de44b1f94471b2e3bdb6b11f57b34d7bc791bb.
Problem
The NVNMD env-mat TensorFlow ops accept tensor-provided neighbor lists (nei_mode == 4) but then ignore the neighbor-list data and rebuild neighbors from coordinates.
Both NVNMD env-mat paths classify mesh.size() > 16 as a tensor-stored neighbor list:
|
int nei_mode = 0; |
|
bool b_nlist_map = false; |
|
if (mesh_tensor.shape().dim_size(0) == 16) { |
|
// lammps neighbor list |
|
nei_mode = 3; |
|
} else if (mesh_tensor.shape().dim_size(0) == 6) { |
|
// manual copied pbc |
|
assert(nloc == nall); |
|
nei_mode = 1; |
|
b_nlist_map = true; |
|
} else if (mesh_tensor.shape().dim_size(0) == 0) { |
|
// no pbc |
|
assert(nloc == nall); |
|
nei_mode = -1; |
|
} else if (mesh_tensor.shape().dim_size(0) > 16) { |
|
// pass neighbor list inside the tensor |
|
nei_mode = 4; |
|
} else if (mesh_tensor.shape().dim_size(0) == 7 || |
|
int nei_mode = 0; |
|
bool b_nlist_map = false; |
|
if (mesh_tensor.shape().dim_size(0) == 16) { |
|
// lammps neighbor list |
|
nei_mode = 3; |
|
} else if (mesh_tensor.shape().dim_size(0) == 6 || |
|
mesh_tensor.shape().dim_size(0) == 7) { |
|
// manual copied pbc |
|
nei_mode = 1; |
|
b_nlist_map = true; |
|
} else if (mesh_tensor.shape().dim_size(0) == 0 || |
|
mesh_tensor.shape().dim_size(0) == 1) { |
|
// no pbc |
|
nei_mode = -1; |
|
} else if (mesh_tensor.shape().dim_size(0) > 16) { |
|
// pass neighbor list inside the tensor |
|
nei_mode = 4; |
|
} else { |
However, the shared NVNMD _prepare_coord_nlist_cpu() treats every mode except 3 as "build nlist by myself":
|
template <typename FPTYPE> |
|
static void _prepare_coord_nlist_cpu(OpKernelContext* context, |
|
FPTYPE const** coord, |
|
std::vector<FPTYPE>& coord_cpy, |
|
int const** type, |
|
std::vector<int>& type_cpy, |
|
std::vector<int>& idx_mapping, |
|
deepmd::InputNlist& inlist, |
|
std::vector<int>& ilist, |
|
std::vector<int>& numneigh, |
|
std::vector<int*>& firstneigh, |
|
std::vector<std::vector<int>>& jlist, |
|
int& new_nall, |
|
int& mem_cpy, |
|
int& mem_nnei, |
|
int& max_nbor_size, |
|
const FPTYPE* box, |
|
const int* mesh_tensor_data, |
|
const int& nloc, |
|
const int& nei_mode, |
|
const float& rcut_r, |
|
const int& max_cpy_trial, |
|
const int& max_nnei_trial) { |
|
inlist.inum = nloc; |
|
if (nei_mode != 3) { |
|
// build nlist by myself |
|
// normalize and copy coord |
|
if (nei_mode == 1) { |
|
int copy_ok = _norm_copy_coord_cpu(coord_cpy, type_cpy, idx_mapping, |
|
new_nall, mem_cpy, *coord, box, *type, |
|
nloc, max_cpy_trial, rcut_r); |
|
OP_REQUIRES(context, copy_ok, |
|
errors::Aborted("cannot allocate mem for copied coords")); |
|
*coord = &coord_cpy[0]; |
|
*type = &type_cpy[0]; |
|
} |
|
// build nlist |
|
int build_ok = _build_nlist_cpu(ilist, numneigh, firstneigh, jlist, |
|
max_nbor_size, mem_nnei, *coord, nloc, |
|
new_nall, max_nnei_trial, rcut_r); |
|
OP_REQUIRES(context, build_ok, |
|
errors::Aborted("cannot allocate mem for nlist")); |
|
inlist.ilist = &ilist[0]; |
|
inlist.numneigh = &numneigh[0]; |
|
inlist.firstneigh = &firstneigh[0]; |
|
} else { |
The non-NVNMD implementation has a separate nei_mode == 4 branch that copies ilist, numneigh, and jlist from the mesh tensor:
|
inlist.inum = nloc; |
|
if (nei_mode != 3 && nei_mode != 4) { |
|
// build nlist by myself |
|
// normalize and copy coord |
|
if (nei_mode == 1) { |
|
int copy_ok = _norm_copy_coord_cpu(coord_cpy, type_cpy, idx_mapping, |
|
new_nall, mem_cpy, *coord, box, *type, |
|
nloc, max_cpy_trial, rcut_r); |
|
OP_REQUIRES(context, copy_ok, |
|
errors::Aborted("cannot allocate mem for copied coords")); |
|
*coord = &coord_cpy[0]; |
|
*type = &type_cpy[0]; |
|
} |
|
// build nlist |
|
int build_ok = _build_nlist_cpu(ilist, numneigh, firstneigh, jlist, |
|
max_nbor_size, mem_nnei, *coord, nloc, |
|
new_nall, max_nnei_trial, rcut_r); |
|
OP_REQUIRES(context, build_ok, |
|
errors::Aborted("cannot allocate mem for nlist")); |
|
inlist.ilist = &ilist[0]; |
|
inlist.numneigh = &numneigh[0]; |
|
inlist.firstneigh = &firstneigh[0]; |
|
} else if (nei_mode == 4) { |
|
std::memcpy(&ilist[0], 16 + mesh_tensor_data, sizeof(int) * nloc); |
|
std::memcpy(&numneigh[0], 16 + nloc + mesh_tensor_data, sizeof(int) * nloc); |
|
for (int ii = 0, kk = 0; ii < nloc; ++ii) { |
|
jlist[ii].resize(numneigh[ii]); |
|
std::memcpy(&jlist[ii][0], 16 + 2 * nloc + kk + mesh_tensor_data, |
|
sizeof(int) * numneigh[ii]); |
|
firstneigh[ii] = &jlist[ii][0]; |
|
kk += numneigh[ii]; |
|
} |
|
inlist.ilist = &ilist[0]; |
|
inlist.numneigh = &numneigh[0]; |
|
inlist.firstneigh = &firstneigh[0]; |
|
} else { |
Impact
Calls to ProdEnvMatANvnmdQuantize or ProdEnvMatAMixNvnmdQuantize with a tensor-stored neighbor list can silently compute descriptors using a rebuilt distance neighbor list instead of the caller-provided list. That is especially risky for tests or integrations that intentionally provide a prefiltered or otherwise non-distance-equivalent neighbor list.
Suggested fix
Mirror the non-NVNMD nei_mode == 4 branch in the NVNMD helper, including the ilist, numneigh, jlist, and firstneigh setup.
Add CPU coverage for both NVNMD env-mat ops where the tensor-provided neighbor list differs from the distance-built neighbor list, and verify the op follows the tensor list.
This issue comes from a Codex global scan of
deepmodeling/deepmd-kitat commit73de44b1f94471b2e3bdb6b11f57b34d7bc791bb.Problem
The NVNMD env-mat TensorFlow ops accept tensor-provided neighbor lists (
nei_mode == 4) but then ignore the neighbor-list data and rebuild neighbors from coordinates.Both NVNMD env-mat paths classify
mesh.size() > 16as a tensor-stored neighbor list:deepmd-kit/source/op/tf/prod_env_mat_multi_device_nvnmd.cc
Lines 410 to 427 in 73de44b
deepmd-kit/source/op/tf/prod_env_mat_multi_device_nvnmd.cc
Lines 662 to 679 in 73de44b
However, the shared NVNMD
_prepare_coord_nlist_cpu()treats every mode except3as "build nlist by myself":deepmd-kit/source/op/tf/prod_env_mat_multi_device_nvnmd.cc
Lines 231 to 276 in 73de44b
The non-NVNMD implementation has a separate
nei_mode == 4branch that copiesilist,numneigh, andjlistfrom the mesh tensor:deepmd-kit/source/op/tf/prod_env_mat_multi_device.cc
Lines 1471 to 1506 in 73de44b
Impact
Calls to
ProdEnvMatANvnmdQuantizeorProdEnvMatAMixNvnmdQuantizewith a tensor-stored neighbor list can silently compute descriptors using a rebuilt distance neighbor list instead of the caller-provided list. That is especially risky for tests or integrations that intentionally provide a prefiltered or otherwise non-distance-equivalent neighbor list.Suggested fix
Mirror the non-NVNMD
nei_mode == 4branch in the NVNMD helper, including theilist,numneigh,jlist, andfirstneighsetup.Add CPU coverage for both NVNMD env-mat ops where the tensor-provided neighbor list differs from the distance-built neighbor list, and verify the op follows the tensor list.