from DSGRN import *

"""
Explanation: Pattern Matching Experiments
End of explanation
"""


network_strings = [ 
["SWI4 : (NDD1)(~YOX1)", "HCM1 : SWI4", "NDD1 : HCM1", "YOX1 : SWI4"],
["SWI4 : (NDD1)(~YOX1)", "HCM1 : SWI4", "NDD1 : HCM1", "YOX1 : (SWI4)(HCM1)"],
["SWI4 : (NDD1)(~YOX1)", "HCM1 : SWI4", "NDD1 : HCM1", "YOX1 : (SWI4)(~HCM1)"],
["SWI4 : (NDD1)(~YOX1)", "HCM1 : SWI4", "NDD1 : HCM1", "YOX1 : (SWI4)(NDD1)"],
["SWI4 : (NDD1)(~YOX1)", "HCM1 : SWI4", "NDD1 : HCM1", "YOX1 : (SWI4)(~NDD1)"],
["SWI4 : (NDD1)(~YOX1)", "HCM1 : (SWI4)(YOX1)", "NDD1 : HCM1", "YOX1 : SWI4"],
["SWI4 : (NDD1)(~YOX1)", "HCM1 : (SWI4)(~YOX1)", "NDD1 : HCM1", "YOX1 : SWI4"],
["SWI4 : (NDD1)(~YOX1)", "HCM1 : SWI4", "NDD1 : (HCM1)(YOX1)", "YOX1 : SWI4"],
["SWI4 : (NDD1)(~YOX1)", "HCM1 : SWI4", "NDD1 : (HCM1)(~YOX1)", "YOX1 : SWI4"] ]

"""
Explanation: Networks
We give two sets of networks. One of them allows for all parameters. The other is identical except it only uses essential parameters.
End of explanation
"""


networks = [Network() for i in range(0,9)]
for i,network in enumerate(networks):
    network.assign('\n'.join(network_strings[i]))

"""
Explanation: Full Networks
End of explanation
"""


essential_network_strings = [ [ line + " : E" for line in network_string ] for network_string in network_strings]
essential_networks = [Network() for i in range(0,9)]
for i,network in enumerate(essential_networks):
    network.assign('\n'.join(essential_network_strings[i]))

"""
Explanation: Essential Networks
End of explanation
"""


def Analyze(network, events, event_ordering):
    poe = PosetOfExtrema(network, events, event_ordering )
    pattern_graph = PatternGraph(poe)
    parameter_graph = ParameterGraph(network)
    result = []
    for parameter_index in range(0, parameter_graph.size()):
        parameter = parameter_graph.parameter(parameter_index)
        search_graph = SearchGraph(DomainGraph(parameter))
        matching_graph = MatchingGraph(search_graph, pattern_graph);
        if PathMatch(matching_graph):
            result.append(parameter_index)
    return [result,  parameter_graph.size()]

"""
Explanation: Path match analysis
We give two functions for path match analysis. One looks at the entire domain graph. The other only checks for path matches in stable Morse sets.
Analysis on entire domain graph
End of explanation
"""


def AnalyzeOnStable(network, events, event_ordering):
    poe = PosetOfExtrema(network, events, event_ordering )
    pattern_graph = PatternGraph(poe)
    parameter_graph = ParameterGraph(network)
    results = []
    for parameter_index in range(0, parameter_graph.size()):
        parameter = parameter_graph.parameter(parameter_index)
        domain_graph = DomainGraph(parameter)
        morse_decomposition = MorseDecomposition(domain_graph.digraph())
        morse_graph = MorseGraph()
        morse_graph.assign(domain_graph, morse_decomposition)
        MorseNodes = range(0, morse_graph.poset().size())
        isStable = lambda node : len(morse_graph.poset().children(node)) == 0
        isStableFC = lambda node : morse_graph.annotation(node)[0] == 'FC' and isStable(node)
        hasStableFC = any( isStableFC(node) for node in MorseNodes)
        StableNodes = [ node for node in MorseNodes if isStable(node) ]
        subresult = []
        for node in StableNodes:
            search_graph = SearchGraph(domain_graph, node)
            matching_graph = MatchingGraph(search_graph, pattern_graph)
            path_match = PathMatch(matching_graph)
            if path_match:
                subresult.append([parameter_index, node])
        results.append([subresult, 1 if hasStableFC else 0])
    return [results, parameter_graph.size()]

"""
Explanation: Analysis on stable Morse set only
End of explanation
"""


original_events = [("HCM1", "min"), ("NDD1", "min"), ("YOX1", "min"), 
          ("SWI4", "max"), ("HCM1", "max"), ("YOX1", "max"), 
          ("NDD1", "max"),
          ("SWI4","min")]
original_event_ordering = [ (i,j) for i in [0,1,2] for j in [3,4,5] ] + \
                 [ (i,j) for i in [3,4,5] for j in [6] ] + \
                 [ (i,j) for i in [6] for j in [7] ]

DrawGraph(PosetOfExtrema(networks[0], original_events, original_event_ordering ))

"""
Explanation: Poset of Extrema
We study two poset of extrema. The first poset comes from looking at times [10,60] and assuming SWI4 happens before the other minima at the beginning and thus can be excluded. The other comes from including all extrema.
Original Poset of Extrema
End of explanation
"""


all_events = [("SWI4", "min"), ("HCM1", "min"), ("NDD1", "min"), ("YOX1", "min"), 
          ("SWI4", "max"), ("HCM1", "max"), ("YOX1", "max"), 
          ("NDD1", "max"),
          ("SWI4","min"),
          ("YOX1", "min"), ("HCM1","min"),
          ("NDD1", "min"),
          ("SWI4", "max"), ("HCM1", "max"), ("YOX1", "max"),
          ("NDD1", "max")]
all_event_ordering = [ (i,j) for i in [0,1,2,3] for j in [4,5,6] ] + \
                 [ (i,j) for i in [4,5,6] for j in [7] ] + \
                 [ (i,j) for i in [7] for j in [8] ] + \
                 [ (i,j) for i in [8] for j in [9,10] ] + \
                 [ (i,j) for i in [9,10] for j in [11,12,13,14] ] + \
                 [ (11,15) ]

DrawGraph(PosetOfExtrema(networks[0], all_events, all_event_ordering ))

"""
Explanation: Alternative Poset of Extrema
End of explanation
"""


def DisplayExperiment(results, title):
    markdown_string = "# " + title + "\n\n"
    markdown_string += "| network | # parameters | # parameters with path match |\n"
    markdown_string += "| ------- |------------ | ---------------------------- |\n"
    for i, item in enumerate(results):
        [parameters_with_path_match, pgsize] = item
        markdown_string += ("|" + str(i) + "|" + str(pgsize) + "|" + str(len(parameters_with_path_match)) + "|\n")
    from IPython.display import display, Markdown, Latex
    display(Markdown(markdown_string))
def DisplayStableExperiment(results, title):
    markdown_string = "# " + title + "\n\n"
    markdown_string += "| network | # parameters | # parameters with stable FC | # parameters with path match |\n"
    markdown_string += "| ------- |------------ | ---------------------------- | ---------------------------- |\n"
    for i, item in enumerate(results):
        [results, pgsize] = item
        parameters_with_path_match = sum([ 1 if pair[0] else 0 for pair in results])
        parameters_with_stable_fc = sum([ 1 if pair[1] else 0 for pair in results])
        markdown_string += ("|" + str(i) + "|" + str(pgsize) + "|" +str(parameters_with_stable_fc) +"|"+str(parameters_with_path_match) + "|\n")
    from IPython.display import display, Markdown, Latex
    display(Markdown(markdown_string))

%%time
experiment = lambda network : Analyze(network, original_events, original_event_ordering)
experimental_results_1 = [ experiment(network) for network in networks ]
DisplayExperiment(experimental_results_1, "Experiment 1: All parameters, original poset of extrema")

%%time
experiment = lambda network : Analyze(network, original_events, original_event_ordering)
experimental_results_2 = [ experiment(network) for network in essential_networks ]
DisplayExperiment(experimental_results_2, "Experiment 2: Essential parameters, original poset of extrema")

%%time
experiment = lambda network : AnalyzeOnStable(network, original_events, original_event_ordering)
experimental_results_3 = [ experiment(network) for network in networks ]
DisplayStableExperiment(experimental_results_3, "Experiment 3: All parameters, original poset, stable only")

%%time
experiment = lambda network : AnalyzeOnStable(network, original_events, original_event_ordering)
experimental_results_4 = [ experiment(network) for network in essential_networks ]
DisplayStableExperiment(experimental_results_4, "Experiment 4: Essential parameters, original poset, stable only")

%%time
experiment = lambda network : Analyze(network, all_events, all_event_ordering)
experimental_results_5 = [ experiment(network) for network in networks ]
DisplayExperiment(experimental_results_5, "Experiment 5: All parameters, alternative poset of extrema")

%%time
experiment = lambda network : Analyze(network, all_events, all_event_ordering)
experimental_results_6 = [ experiment(network) for network in essential_networks ]
DisplayExperiment(experimental_results_6, "Experiment 6: Essential parameters, alternative poset of extrema")

%%time
experiment = lambda network : AnalyzeOnStable(network, all_events, all_event_ordering)
experimental_results_7 = [ experiment(network) for network in networks ]
DisplayStableExperiment(experimental_results_7, "Experiment 7: All parameters, alternative poset of extrema, stable only")

%%time
experiment = lambda network : AnalyzeOnStable(network, all_events, all_event_ordering)
experimental_results_8 = [ experiment(network) for network in essential_networks ]
DisplayStableExperiment(experimental_results_8, "Experiment 8: Essential parameters, alternative poset of extrema, stable only")

"""
Explanation: Experiments
There are 8 experiements corresponding to 3 binary choices:

Full networks vs Essential networks 
Path matching in entire domain graph vs path matching in stable Morse sets
Original poset of extrema vs Alternative poset of extrema
End of explanation
"""


