github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/simulation/transition_matrix.go (about)

     1  package simulation
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  )
     7  
     8  // TransitionMatrix is _almost_ a left stochastic matrix.  It is technically
     9  // not one due to not normalizing the column values.  In the future, if we want
    10  // to find the steady state distribution, it will be quite easy to normalize
    11  // these values to get a stochastic matrix.  Floats aren't currently used as
    12  // the default due to non-determinism across architectures
    13  type TransitionMatrix struct {
    14  	weights [][]int
    15  	// total in each column
    16  	totals []int
    17  	n      int
    18  }
    19  
    20  // CreateTransitionMatrix creates a transition matrix from the provided weights.
    21  // TODO: Provide example usage
    22  func CreateTransitionMatrix(weights [][]int) (TransitionMatrix, error) {
    23  	n := len(weights)
    24  	for i := 0; i < n; i++ {
    25  		if len(weights[i]) != n {
    26  			return TransitionMatrix{},
    27  				fmt.Errorf("transition matrix: non-square matrix provided, error on row %d", i)
    28  		}
    29  	}
    30  	totals := make([]int, n)
    31  	for row := 0; row < n; row++ {
    32  		for col := 0; col < n; col++ {
    33  			totals[col] += weights[row][col]
    34  		}
    35  	}
    36  	return TransitionMatrix{weights, totals, n}, nil
    37  }
    38  
    39  // NextState returns the next state randomly chosen using r, and the weightings
    40  // provided in the transition matrix.
    41  func (t TransitionMatrix) NextState(r *rand.Rand, i int) int {
    42  	randNum := r.Intn(t.totals[i])
    43  	for row := 0; row < t.n; row++ {
    44  		if randNum < t.weights[row][i] {
    45  			return row
    46  		}
    47  		randNum -= t.weights[row][i]
    48  	}
    49  	// This line should never get executed
    50  	return -1
    51  }
    52  
    53  // GetMemberOfInitialState takes an initial array of weights, of size n.
    54  // It returns a weighted random number in [0,n).
    55  func GetMemberOfInitialState(r *rand.Rand, weights []int) int {
    56  	n := len(weights)
    57  	total := 0
    58  	for i := 0; i < n; i++ {
    59  		total += weights[i]
    60  	}
    61  	randNum := r.Intn(total)
    62  	for state := 0; state < n; state++ {
    63  		if randNum < weights[state] {
    64  			return state
    65  		}
    66  		randNum -= weights[state]
    67  	}
    68  	// This line should never get executed
    69  	return -1
    70  }