<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def displ_single(self, g_num, at_1, at_2):
 """ Displacement vector between two atoms. Returns the displacement vector pointing from `at_1` toward `at_2` from geometry `g_num`. If `at_1` == `at_2` a strict zero vector is returned. Displacement vector is returned in units of Bohrs. Parameters g_num |int| -- Index of the desired geometry at_1 |int| -- Index of the first atom at_2 |int| -- Index of the second atom Returns ------- displ length-3 |npfloat_| -- Displacement vector from `at_1` to `at_2` Raises ------ ~exceptions.IndexError If an invalid (out-of-range) `g_num` or `at_#` is provided """


        # Library imports
        import numpy as np
        from .utils import safe_cast as scast

        # The below errors are explicitly thrown since they are multiplied by
        #  three when they are used as an index and thus give non-intuitive
        #  errors.
        # Complain if at_1 is invalid
        if not (-self.num_atoms <= at_1 < self.num_atoms):
            raise IndexError("Invalid index for 'at_1' ({0})".format(at_1))

        # Complain if at_2 is invalid
        if not (-self.num_atoms <= at_2 < self.num_atoms):
            raise IndexError("Invalid index for 'at_2' ({0})".format(at_2))

        # Should never be necessary (save for badly erroneous calling code),
        #  but coerce at_1 and at_2 to their floor() values.  This is again
        #  needed since they are multiplied by three in the index expresssions
        #  below, and can cause funny behavior when truncated by the indexing
        at_1 = scast(np.floor(at_1), np.int_)
        at_2 = scast(np.floor(at_2), np.int_)

        # If the atom indices are the same, return trivial zero vector
        if (at_1 % self.num_atoms) == (at_2 % self.num_atoms):
            return np.array([0.0, 0.0, 0.0])
        ## end if

        # Retrieve the geometry; np.float_ type should be retained
        g = self.geom_single(g_num)

        # Calculate the displacement vector and return
        displ = np.array([ g[i + 3*at_2] - g[i + 3*at_1] for i in range(3) ])

        # Return the displacement vector
        return displ