def build_MDP(X:list[list], D:int, phi=CART(max_depth=3)):
    '''
    X: the dataset to classify/regress. The last column should be 
    target labels.
    D: max tree depth.
    phi: a state dependent function returning test nodes.
    returns: a MDP as a list of lists of states (a list for each depth).
    '''
    d = 0 # Current depth.
    root = State(X, d) # Inital state is the full dataset at depth 0.
    MDP = [[root], []] 
    
    while d < D + 1:
        for state in MDP[d]:
            if d < D: # Only add new nodes states if 
                      # max depth D is not reached.
                # The tests generating function returns test nodes, 
                # splitted datasets and probabilities.
                features, thresholds, Xl, Xr, pl, pr = phi(state)
                for feat, thresh in zip(features, thresholds):
                    left = State(Xl, d+1)
                    right = State(Xr, d+1)
                    MDP[d+1].extend([left, right])
                    action = (feat, thresh)
                    reward = 'zeta'
                    state.transition(action, pl, left, reward)
                    state.transition(action, pr, right, reward)

            #compute best label action
            label_occurences = count(state.X[-1])
            most_prob_label = argmax(label_occurences)
            action = most_prob_label
            reward = label_occurences[most_prob_label]/len(state.X[-1])
            state.transition(action, 1, "terminal_state", reward-1)
    return MDP


                    
