7

I've been working on a Google foobar problem for a couple of days and have all but one test passing, and I'm pretty stuck at this point. Let me know if you have any ideas! I'm using a method described here, and I have a working example up on repl.it here. Here's the problem spec:

Doomsday Fuel

Making fuel for the LAMBCHOP's reactor core is a tricky process because of the exotic matter involved. It starts as raw ore, then during processing, begins randomly changing between forms, eventually reaching a stable form. There may be multiple stable forms that a sample could ultimately reach, not all of which are useful as fuel.

Commander Lambda has tasked you to help the scientists increase fuel creation efficiency by predicting the end state of a given ore sample. You have carefully studied the different structures that the ore can take and which transitions it undergoes. It appears that, while random, the probability of each structure transforming is fixed. That is, each time the ore is in 1 state, it has the same probabilities of entering the next state (which might be the same state). You have recorded the observed transitions in a matrix. The others in the lab have hypothesized more exotic forms that the ore can become, but you haven't seen all of them.

Write a function answer(m) that takes an array of array of nonnegative ints representing how many times that state has gone to the next state and return an array of ints for each terminal state giving the exact probabilities of each terminal state, represented as the numerator for each state, then the denominator for all of them at the end and in simplest form. The matrix is at most 10 by 10. It is guaranteed that no matter which state the ore is in, there is a path from that state to a terminal state. That is, the processing will always eventually end in a stable state. The ore starts in state 0. The denominator will fit within a signed 32-bit integer during the calculation, as long as the fraction is simplified regularly.

*For example, consider the matrix m:

[
  [0,1,0,0,0,1],  # s0, the initial state, goes to s1 and s5 with equal probability
  [4,0,0,3,2,0],  # s1 can become s0, s3, or s4, but with different probabilities
  [0,0,0,0,0,0],  # s2 is terminal, and unreachable (never observed in practice)
  [0,0,0,0,0,0],  # s3 is terminal
  [0,0,0,0,0,0],  # s4 is terminal
  [0,0,0,0,0,0],  # s5 is terminal
]

So, we can consider different paths to terminal states, such as:

s0 -> s1 -> s3
s0 -> s1 -> s0 -> s1 -> s0 -> s1 -> s4
s0 -> s1 -> s0 -> s5

Tracing the probabilities of each, we find that s2 has probability 0 s3 has probability 3/14 s4 has probability 1/7 s5 has probability 9/14 So, putting that together, and making a common denominator, gives an answer in the form of [s2.numerator, s3.numerator, s4.numerator, s5.numerator, denominator] which is [0, 3, 2, 9, 14].*

Test cases

Inputs:
    (int) m = [[0, 2, 1, 0, 0], [0, 0, 0, 3, 4], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
Output:
    (int list) [7, 6, 8, 21]

Inputs:
    (int) m = [[0, 1, 0, 0, 0, 1], [4, 0, 0, 3, 2, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
Output:
    (int list) [0, 3, 2, 9, 14]

Here's my code so far.

from __future__ import division
from itertools import compress
from itertools import starmap
from operator import mul
import fractions


def convertMatrix(transMatrix):
  probMatrix = []
  for i in range(len(transMatrix)):
    row = transMatrix[i]
    newRow = []
    rowSum = sum(transMatrix[i])
    if all([v == 0 for v in transMatrix[i]]):
      for j in transMatrix[i]:
        newRow.append(0)
      newRow[i] = 1
      probMatrix.append(newRow)
    else:
      for j in transMatrix[i]:
        if j == 0:
          newRow.append(0)
        else:
          newRow.append(j/rowSum)
      probMatrix.append(newRow)
  return probMatrix



def answer(m):
  # convert matrix numbers into probabilities
  probMatrix = convertMatrix(m)

  # find terminal states
  terminalStateFilter = []
  for row in range(len(m)):
    if all(x == 0 for x in m[row]):
      terminalStateFilter.append(True)
    else:
      terminalStateFilter.append(False)

  # multiply matrix by probability vector
  oldFirstRow = probMatrix[0]
  probVector = None
  for i in range(3000):
    probVector = [sum(starmap(mul, zip(oldFirstRow, col))) for col in zip(*probMatrix)]
    oldFirstRow = probVector

  # generate numerators
  numerators = []
  for i in probVector:
    numerator = fractions.Fraction(i).limit_denominator().numerator
    numerators.append(numerator)

  # generate denominators
  denominators = []
  for i in probVector:
    denominator = fractions.Fraction(i).limit_denominator().denominator
    denominators.append(denominator)

  # calculate factors to multiply numerators by
  factors = [max(denominators)/x for x in denominators]
  # multiply numerators by factors
  numeratorsTimesFactors = [a*b for a,b in zip(numerators, factors)]
  # filter numerators by terminal state booleans
  terminalStateNumerators = list(compress(numeratorsTimesFactors, terminalStateFilter))

  # append numerators and denominator to answer
  answerlist = []
  for i in terminalStateNumerators:
    answerlist.append(i)
  answerlist.append(max(denominators))

  return list(map(int, answerlist))
  • 1
    Welcome to StackOverflow. Please read and follow the posting guidelines in the help documentation. [Minimal, complete, verifiable example](http://stackoverflow.com/help/mcve) applies here. We cannot effectively help you until you post your MCVE code and accurately describe the problem. Specifically, we need to know what test fails, the output you got, the output you expected, and the intermediate results you've traced so far in debugging the problem. – Prune Jan 27 '17 at 20:02
  • Hi. That's the problem, I don't know what the tests are, so I'm just trying to figure out if I'm missing a special case, or if it's failing because it's too slow. I'm only able to execute the matrix multiplication up to 7000 times before I get a timeout. – Michael Caterisano Jan 27 '17 at 20:29
  • 1
    https://math.stackexchange.com/questions/1941244/markov-chain-help – Robin Mackenzie May 20 '17 at 02:12
  • That's a great resource, Robin. I found it when I was working on the problem. Thanks! – Michael Caterisano Aug 07 '17 at 04:45

0 Answers0