简体   繁体   中英

Numpy array assignment to column failing ONLY after first iteration

I have a strange bug in this naive code for Gram-schmidt orthogonalization I wrote for numpy ( v1.21.2 ).

def gram_schmidt(basis):
    """
    Compute orthogonal basis from given basis.
    
    Parameters:
        basis <- an mxn array-like of vectors in m-space
    Returns:
        orthogonalized basis as array of shape (m,n)
    """
    m, n = basis.shape
    orthobasis = np.zeros_like(basis)
    quadrances = np.ones(n)
    
    for i, b in enumerate(basis.T):
        # initial iteration
        if i == 0:
            orthobasis[:, i] = b
            quadrances[i] = b.T @ b
            continue
        
        # subsequent iterations
        # get the orthogonal complement vector as the next basis vector in the set
        # 1: project onto subspace generated by basis accumulated so far
        P = orthobasis[:, :i]
        proj_b = P @ ((P.T @ b) / quadrances[:i])
        # 2: get the orthogonal vector to the projection
        e = b - proj_b
        # 3: add this orthogonal vector to the basis being constructed
        orthobasis[:, i] = e
        # 4: add the quadrance of the new vector
        quadrances[i] = e.T @ e
        
        print(f"**iteration {i}**\nb = {b}\nP = {P}\nproj_b = {proj_b}\ne = {e}\northobasis =\n{orthobasis}")
        print("-" * 100)
        
    return orthobasis

When I run this code with the following input:

basis = np.stack([ np.array(v) for v in
     [[1,1,1,1],
      [0,1,1,1],
      [0,0,1,1]] ],
                 axis=1)
gram_schmidt(basis)

I get the output:

**iteration 1**
b = [0 1 1 1]
P = [[1]
 [1]
 [1]
 [1]]
proj_b = [0.75 0.75 0.75 0.75]
e = [-0.75  0.25  0.25  0.25]
orthobasis =
[[1 0 0]
 [1 0 0]
 [1 0 0]
 [1 0 0]]
----------------------------------------------------------------------------------------------------
**iteration 2**
b = [0 0 1 1]
P = [[1 0]
 [1 0]
 [1 0]
 [1 0]]
proj_b = [0.5 0.5 0.5 0.5]
e = [-0.5 -0.5  0.5  0.5]
orthobasis =
[[1 0 0]
 [1 0 0]
 [1 0 0]
 [1 0 0]]

So the unexpected behavior is that step 3 in the gram_schmidt function does not assign the computed array e to the i-th column of orthobasis . You can ignore the correctness of gram_schmidt as the problem is related to array assignment: the first iteration assigns successfully to the first column, yet the subsequent iterations silently fail. What is even more odd is that if I change e in step 3 to a hard-coded array (of conforming shape with columns of orthobasis ), it assigns successfully, In the output you can see that starting from the second iteration (iteration 1), there is no change to the columns of orthobasis ; they are always 0!

I am so confused and have lost hours debugging this. I appreciate any assistance!

Each numpy array has a specified data type and can contain elements only of this type. In your example basis is an array of integers. Then you are initializing orthobasis using

orthobasis = np.zeros_like(basis)

This makes the data type of orthobasis the same as basis , ie it is an array of integers too. When you try to modify entries of this array by assigning to them floats values, these floats are first converted to integers by rounding them toward 0. Thus the array [-0.5 -0.5 0.5 0.5] becomes an array of zeros.

To fix it, you can initialize orthobasis as an array of floats:

orthobasis = np.zeros_like(basis, dtype=float)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM