2

The problem and what I expect.

I have a table h which indicates the H-bond states, where 1 for existing H-bond, 0 for no H-bond exist. Colums are for different object, rows are for different time step.

0, 0, 1, 1, 0, 0
0, 0, 1, 1, 0, 0
1, 0, 1, 1, 0, 0
1, 1, 1, 1, 0, 1
0, 1, 0, 0, 1, 1
0, 1, 0, 0, 1, 1
1, 0, 1, 1, 0, 1

I want to calculate the life (how long the H-bond exists) for each object. So the expected life table L should be like this.

0, 0, 4, 4, 0, 0
0, 0, 4, 4, 0, 0 
2, 0, 4, 4, 0, 0 
2, 3, 4, 4, 0, 4
0, 3, 0, 0, 2, 4
0, 3, 0, 0, 2, 4
1, 0, 1, 1, 0, 4

I don't know how to apply this map.

What I've done.

I've tried to map h to a new table generations indicating the generations of H-bond using the rising edge detecting. And the generations table G obtained:

 [[0 0 1 1 0 0]
 [0 0 1 1 0 0]
 [1 0 1 1 0 0]
 [1 1 1 1 0 1]
 [1 1 1 1 1 1]
 [1 1 1 1 1 1]
 [2 1 2 2 1 1]]

And then I tried to map h to a new ages table, indicating the ages of H-bond. I got the following table A.

 [[0 0 1 1 0 0]
 [0 0 2 2 0 0]
 [1 0 3 3 0 0]
 [2 1 4 4 0 1]
 [0 2 0 0 1 2]
 [0 3 0 0 2 3]
 [1 0 1 1 0 4]]

I was tried to map h to life table L by using the logic: The life of a H-bond is the maximum age of all ages with the same generation. However, I've stuck on this mapping.

Some code

Some codes I used to calculate G and A.

    def getQbGenerations(self, QbStates):
        QbGenerations = np.zeros_like(QbStates, dtype=np.int64)
        Generation = np.zeros(QbStates.shape[-1])
        Generation[QbStates[0] == 1] = 1
        QbGenerations[0] = Generation
        for i in range(1, QbStates.shape[0]):
            # Rising Edge
            RiseMask = np.logical_and(QbStates[i-1]==0, QbStates[i]==1)
            Generation[RiseMask] += 1
            QbGenerations[i] = Generation
        return QbGenerations

    def getQbAges(self, QbStates):
        QbAges = np.zeros_like(QbStates, dtype=np.int64)
        Age = np.zeros(QbStates.shape[-1])
        Age[QbStates[0] == 1] = 1
        QbAges[0] = Age
        for i in range(1, QbStates.shape[0]):
            BondMask = QbStates[i] == 1
            Age[BondMask] += 1
            Age[~BondMask] = 0
            QbAges[i] = Age
        return QbAges
Jack Huang
  • 31
  • 4

3 Answers3

1

Thanks to the find_runs.py.

Another answer is:

import numpy as np


def find_runs(x):
    """Find runs of consecutive items in an array."""
    # ensure array
    x = np.asanyarray(x)
    if x.ndim != 1:
        raise ValueError('only 1D array supported')
    n = x.shape[0]

    # handle empty array
    if n == 0:
        return np.array([]), np.array([]), np.array([])

    else:
        # find run starts
        loc_run_start = np.empty(n, dtype=bool)
        loc_run_start[0] = True
        np.not_equal(x[:-1], x[1:], out=loc_run_start[1:])
        run_starts = np.nonzero(loc_run_start)[0]

        # find run values
        run_values = x[loc_run_start]

        # find run lengths
        run_lengths = np.diff(np.append(run_starts, n))

        return run_values, run_starts, run_lengths


if __name__ == "__main__":
    QbStates = np.array([
                    [0, 0, 1, 1, 0, 0],
                    [0, 0, 1, 1, 0, 0],
                    [1, 0, 1, 1, 0, 0],
                    [1, 1, 1, 1, 0, 1],
                    [0, 1, 0, 0, 1, 1],
                    [0, 1, 0, 0, 1, 1],
                    [1, 0, 1, 1, 0, 1]])

    print('QbStates: \n{}'.format(QbStates))
    lifes = np.array([], dtype=np.int64).reshape(0,QbStates.shape[0])
    for row in QbStates.T:
        values, positions, times = find_runs(row)
        life = np.array([],dtype=np.int64)
        for v, t in zip(values, times):
            life = np.append(life, np.repeat(v*t,t))
        lifes = np.vstack([lifes, life])
    
    # Transpose to get the answer
    print('LifeStates:\n {}'.format(lifes.T))

The result obtained.

QbStates: 
[[0 0 1 1 0 0]
 [0 0 1 1 0 0]
 [1 0 1 1 0 0]
 [1 1 1 1 0 1]
 [0 1 0 0 1 1]
 [0 1 0 0 1 1]
 [1 0 1 1 0 1]]
LifeStates:
 [[0 0 4 4 0 0]
 [0 0 4 4 0 0]
 [2 0 4 4 0 0]
 [2 3 4 4 0 4]
 [0 3 0 0 2 4]
 [0 3 0 0 2 4]
 [1 0 1 1 0 4]]
Jack Huang
  • 31
  • 4
0

I would do something much simpler, albeit not the most 'pythonic' solution. I'd use the following algorithm:

  1. Take each column

  2. Loop through the column until a non-zero entry is reached

  3. Record how long the 'streak' of non-zero entries is

  4. Add this to a list

  5. Reloop through the column

  6. Identify the first streak

  7. Change the values in the first streak to the first entry in the list above.

Dharman
  • 30,962
  • 25
  • 85
  • 135
0

Note that you have obtain the array A, we can continue from A. If use an algorithm based on gradient along the frame-axis, then we can obtain the expected array L.

# The array: Age
A= np.array([[0,0,1,1,0,0],
 [0,0,2,2,0,0],
 [1,0,3,3,0,0],
 [2,1,4,4,0,1],
 [0,2,0,0,1,2],
 [0,3,0,0,2,3],
 [1,0,1,1,0,4]])

# Define two parameters
age = A.T
n = age.shape[0]
m = age.shape[1]

# Generate the gradient along frame-axis for the array A
# output: a new array grad_age
grad_age = np.zeros((n, m))
for i in range(n):
    for j in range(m):
        if j < m-1:
            grad_age[i][j] = age[i][j+1] - age[i][j]
        else: # In the old version, this condition was neglected.
            grad_age[i][m-1] = 0 - age[i][m-1]
            
print("The array grad_age:")            
print(grad_age)

# Find out the locations of elements in the array 'age' 
# which are of negative gradient and modify related 
# elements in the array 'age'

for i in range(n):
    for j in reversed(range(m)):       
        t = grad_age[i][j]
        if t < 0:     #find out these index where gradient < 0
            print(t) # for checking
            for x in range(abs(int(t))):
                age[i][j-x] += x
print("The array L:")                
print(age.T)

The result is:

The array grad_age:
[[ 0.  1.  1. -2.  0.  1. -1.]
 [ 0.  0.  1.  1.  1. -3.  0.]
 [ 1.  1.  1. -4.  0.  1. -1.]
 [ 1.  1.  1. -4.  0.  1. -1.]
 [ 0.  0.  0.  1.  1. -2.  0.]
 [ 0.  0.  1.  1.  1.  1. -4.]]
-1.0
-2.0
-3.0
-1.0
-4.0
-1.0
-4.0
-2.0
-4.0
The array L:
[[0 0 4 4 0 0]
 [0 0 4 4 0 0]
 [2 0 4 4 0 0]
 [2 3 4 4 0 4]
 [0 3 0 0 2 4]
 [0 3 0 0 2 4]
 [1 0 1 1 0 4]]
jiadong
  • 318
  • 5
  • 16