github.com/Finschia/finschia-sdk@v0.48.1/x/simulation/transition_matrix.go (about)

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