hklarner / pyboolnet

PyBoolNet is a Python package for the generation, modification and analysis of Boolean networks.
43 stars 21 forks source link

Order of nodes in trap space results (#question) #31

Closed bblodfon closed 3 years ago

bblodfon commented 4 years ago

Hi Hannes,

I was benchmarking your tool against the trapspace calculation (the terminal/minimum ones are the ones that interest me) provided by BioLQM. It is by far faster than BioLQM's BDD-based algorithm (which is faster than the ASP/clingo-based option they have for trapspaces). Their code was relatively easy to integrate though since my application is in Java (I was script-testing your tool and I made sure that in both cases I was testing just the trapspace calculation and nothing more).

So, when I was crosschecking the results between the two tools I found that you change the order of the nodes in the trapspace vector result (while BioLQM keeps that node sequence as it is read from the .bnet file): This is a sample code to calculate the trapspaces for the grieco_mapk.bnet file and output the nodes:

import PyBoolNet                                                                

from PyBoolNet import FileExchange                                              
from PyBoolNet import InteractionGraphs as IGs                                  
from PyBoolNet import StateTransitionGraphs as STGs                             
from PyBoolNet import AspSolver                                                 

primes_mapk = FileExchange.bnet2primes("grieco_mapk.bnet")                      
print("\nTrap spaces for grieco_mapk.bnet:\n")                                  

traps = AspSolver.trap_spaces(primes_mapk, "min")                             

print(", ".join(STGs.subspace2str(primes_mapk, x) for x in traps))            
print("#Trapspaces: ", len(traps)) 

igraph = IGs.primes2igraph(primes_mapk)                                         
print(igraph.nodes())                                         

My question: is there a way to have the trapspace results in the order of the .bnet file/network they came from without me changing manually the resulting strings based on the original node sequence? And, out of curiosity, why it was implemented like that?

BR, John.

hklarner commented 4 years ago

Hi John. Without looking further into the code: I remember that I wanted to have the nodes ordered so that equality checks are independent of the order in which you specify a network. Also when I printed equations I wanted them sorted alphabetically to find variables quicker. I understand that there are good reasons to have the order of the variables in a trap space be user defined. For example all inputs first and all outputs last. Isn't one solution to write your own mapper? Suppose you want to print the trap space with variables in the order a,c,d,b instead of a,b,c,d:

my_printer = lambda trap: ''.join(trap[x] for x in ['a','c','d','b'])

Does this work for you?

bblodfon commented 4 years ago

Hi Hannes,

Thanks for giving me the reasons behind that particular implementation.

I believe that the "normal" node ordering sequence (as they are presented while the .bnet file is read that is) should be the first/default option and the sorted-order an extra. The reason is that a user (like me per se) has already defined files with the sequence as he wanted (as for the example you gave with the inputs first and the outputs last) - so wouldn't it make sense to get the attractor results in the same node order? Think about it this way: since PyBoolNet is mostly used for scripting/workflow purposes, the user-defined aspect you mentioned has already been set in the model definition (that is the creation of the boolean model file with the order of the equations/nodes as they are there) - changing them afterwards to be as they were in the model, seems a needless post-processing of results to me!

Writing a mapper such as the one you provided is no problem, it's another thing I am stressing here :)

BR, John.

hklarner commented 4 years ago

As I said, I think you can argue both ways. And I can see your point that often care is taken in defining a node sequence.

Technically, I don't see a place to remember the ordering of the nodes in a network. The prime implicants are just dictionaries and once they are created from a bnet file (via FileExchange.bnet2primes) they are without order. Do you see a way of remembering node order?

bblodfon commented 4 years ago

I am not a Python programer, but I saw this post, so maybe using Python >= 3.7 is a solution without you having to do any change in the code? I am using Anaconda's 3.6 version - I will try to test one of these days with the 3.7 version to see if the ordering is preserved - can you maybe also test it? Also maybe using OrderedDict could be a solution as well...

In case this works it would be also nice to add something about this in the doc!

hklarner commented 4 years ago

Cool! I think using ordered dicts is definitely an option! I will look into this and get back to you.

bblodfon commented 4 years ago

Ok, thanks! I just tested it with Python versions: 3.6.9 and 3.7.5 and there was no change in the order, so OrderedDict seems to be the only clean way forward.