def __call__ (self, reduced_parameter_index): """ The query returns a graph which contains the poset of gene parameter indices corresponding to adjusting the parameter by changing the logic parameter associated with the gene being queried. The graph is as follows: * The vertices of the graph are named according to Gene Parameter Index (gpi). * There is a directed edge p -> q iff p < q and the associated logic parameters are adjacent. * The graph is labelled with pairs (Parameter index, Morse graph index). In addition the following extra structures are provided: * `graph.data` is a dictionary from gene parameter index to (hex code, parameter index, morse graph index) * `graph.mgi` is a function which accepts a gpi and returns the associated Morse graph index * `graph.num_inputs` is the number of network edges which are inputs to the gene associated with the query * `graph.num_outputs`is the number of network edges which are outputs to the gene associated with the query * `graph.essential` is a boolean-valued function which determines if each vertex corresponds to an essential parameter node """ LogToSTDOUT("SingleGeneQuery(" + str(reduced_parameter_index) + ")") c = self.database.execute("select GeneParameterIndex,ParameterIndex,MorseGraphIndex from " + self.gene + " where ReducedParameterIndex=?", (str(reduced_parameter_index),)) LogToSTDOUT("SingleGeneQuery: SQL statement executed") Q = { row[0] : (self.hexcodes[row[0]], row[1], row[2]) for row in c } LogToSTDOUT("SingleGeneQuery: Q constructed") graph = self.graph.clone() LogToSTDOUT("SingleGeneQuery: graph constructed") graph.data = Q graph.mgi = lambda gpi : graph.data[gpi][2] graph.label = lambda gpi : str(graph.data[gpi][1]) + ':' + str(graph.data[gpi][2]) graph.num_inputs = len(self.database.network.inputs(self.gene_index)) graph.num_outputs = len(self.database.network.outputs(self.gene_index)) graph.essential = lambda gpi : essential(graph.data[gpi][0],graph.num_inputs,graph.num_outputs) LogToSTDOUT("SingleGeneQuery: graph attributes emplaced") return graph
def __init__(self, database): LogToSTDOUT("MonostableQuery :: initializing") self.database = database if not hasattr(database, 'MonostableQuery'): c = database.conn.cursor() LogToSTDOUT( "MonostableQuery :: select MorseGraphIndex from (select MorseGraphIndex, count(*) as StableCount from (select MorseGraphIndex,Vertex from MorseGraphVertices except select MorseGraphIndex,Source from MorseGraphEdges) group by MorseGraphIndex) where StableCount=1;" ) sqlexpression = "select MorseGraphIndex from (select MorseGraphIndex, count(*) as StableCount from (select MorseGraphIndex,Vertex from MorseGraphVertices except select MorseGraphIndex,Source from MorseGraphEdges) group by MorseGraphIndex) where StableCount=1;" database.MonostableQuery = frozenset( [row[0] for row in c.execute(sqlexpression)]) LogToSTDOUT("MonostableQuery :: constructed")
def __init__(self, database, bounds): self.database = database LogToSTDOUT("SingleFixedPointQuery :: initializing") LogToSTDOUT("SingleFixedPointQuery :: calling MatchQuery") MatchQuery(bounds, "Matches", database) # Final query and print results c = database.conn.cursor() LogToSTDOUT( "SingleFixedPointQuery :: select MorseGraphIndex from Matches;") self.set_of_matches = set([ row[0] for row in c.execute('select MorseGraphIndex from Matches;') ]) #result = [row[0] for row in c.execute('select distinct ParameterIndex from Matches natural join Signatures order by ParameterIndex;')] LogToSTDOUT("SingleFixedPointQuery :: drop table Matches;") c.execute('drop table Matches') LogToSTDOUT("SingleFixedPointQuery :: constructed")
def __call__(self, reduced_parameter_index): LogToSTDOUT("HysteresisQuery(" + str(reduced_parameter_index) + ")") # DEBUG searchgraph = self.GeneQuery(reduced_parameter_index) LogToSTDOUT("HysteresisQuery: Search Graph Constructed.") # DEBUG searchgraph.matching_label = lambda v: self.matching_label( searchgraph.mgi(v)) searchgraphstring = ''.join( [searchgraph.matching_label(v) for v in searchgraph.vertices]) if searchgraphstring not in self.memoization_cache: alignment_graph = AlignmentGraph(searchgraph, self.patterngraph, self.matching_relation) LogToSTDOUT( "HysteresisQuery: Alignment Graph Constructed.") # DEBUG LogToSTDOUT("HysteresisQuery: Alignment Graph has " + str(len(alignment_graph.vertices)) + " vertices") # DEBUG LogToSTDOUT("HysteresisQuery: Alignment Graph has " + str(len(alignment_graph.edges)) + " edges") # DEBUG root_vertex = (0, 0) leaf_vertex = (len(searchgraph.vertices) - 1, 4) is_reachable = alignment_graph.reachable(root_vertex, leaf_vertex) #number_of_paths = alignment_graph.numberOfPaths(root_vertex, leaf_vertex) LogToSTDOUT("HysteresisQuery: Reachability computed.") # DEBUG self.memoization_cache[searchgraphstring] = is_reachable LogToSTDOUT("HysteresisQuery: Returning.") # DEBUG return self.memoization_cache[searchgraphstring]
def __init__(self, database, gene, quiescent_bounds, proliferative_bounds): """ In order to perform hysteresis queries we must first categorize each Morse graph as either 'Q' monostable quiescent, 'P' monostable proliferative, 'q' quiescent, 'p' proliferative, 'B' bistable, or 'O' other We assume the quiescent and proliferative FP states are given by disjoint bounding rectangles """ LogToSTDOUT("HysteresisQuery(" + str(database.dbname) + ", " + str(gene) + ")") self.database = database self.gene = gene # Create query object to check if morse graph indices have quiescent FP as only minimal morse node LogToSTDOUT("HysteresisQuery :: MonostableFixedPointQuery(" + str(database.dbname) + ", " + str(quiescent_bounds) + ")") Q = MonostableFixedPointQuery(database, quiescent_bounds) # Create query object to check if morse graph indices has quiescent FP LogToSTDOUT("HysteresisQuery :: SingleFixedPointQuery(" + str(database.dbname) + ", " + str(quiescent_bounds) + ")") q = SingleFixedPointQuery(database, quiescent_bounds) # Create query object to check if morse graph indices have proliferative FP as only minimal morse node LogToSTDOUT("HysteresisQuery :: MonostableFixedPointQuery(" + str(database.dbname) + ", " + str(proliferative_bounds) + ")") P = MonostableFixedPointQuery(database, proliferative_bounds) # Create query object to check if morse graph indices has proliferative FP LogToSTDOUT("HysteresisQuery :: SingleFixedPointQuery(" + str(database.dbname) + ", " + str(proliferative_bounds) + ")") p = SingleFixedPointQuery(database, proliferative_bounds) # Check query object to check if morse graph index has both quiescent FP and proliferative FP LogToSTDOUT("HysteresisQuery :: DoubleFixedPointQuery(" + str(database.dbname) + ", " + str(quiescent_bounds) + ", " + str(proliferative_bounds) + ")") B = DoubleFixedPointQuery(database, quiescent_bounds, proliferative_bounds) # Create a labelling function which accepts a morse graph index and returns Q, P, B, p, q, or O # Note: case fallthrough order matters here self.matching_label = lambda mgi: 'Q' if Q(mgi) else ('P' if P( mgi) else ('B' if B(mgi) else ('q' if q(mgi) else ('p' if p(mgi) else 'O')))) # Create the pattern graph to represent Q -> B -> P (with self-loop on Q, B, and P) self.patterngraph = Graph(set([0, 1, 2, 3, 4]), [(0, 0), (1, 1), (0, 1), (1, 0), (0, 2), (1, 2), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (4, 4), (4, 3)]) self.patterngraph.matching_label = lambda v: { 0: 'Q', 1: 'q', 2: 'B', 3: 'p', 4: 'P' }[v] # Create matching relation (in this case we just check for equality of the matching labels) self.matching_relation = lambda label1, label2: label1 == label2 # Create SingleGeneQuery object LogToSTDOUT("HysteresisQuery :: SingleGeneQuery(" + str(database.dbname) + ", " + str(gene) + ")") self.GeneQuery = SingleGeneQuery(database, gene) self.memoization_cache = {}
def MatchQuery(bounds, outputtablename, database): # Parse the command line LogToSTDOUT("MatchQuery(" + str(bounds) + ", " + str(outputtablename) + ")") c = database.conn.cursor() expressions = buildQueryExpression(bounds, database) LogToSTDOUT("MatchQuery :: built expressions " + str(expressions)) N = len(expressions) for i, expression in enumerate(expressions): oldtable = 'tmpMatches' + str(i) if i == 0: oldtable = "MorseGraphAnnotations" newtable = 'tmpMatches' + str(i + 1) if i == N - 1: newtable = outputtablename sql_string = 'create temp table ' + newtable + ' as select * from ' + oldtable + ' where ' + expression + ';' LogToSTDOUT("MatchQuery :: " + sql_string) c.execute(sql_string) if i > 0: c.execute('drop table ' + oldtable) LogToSTDOUT("MatchQuery :: constructed")
def __init__(self, database, gene): LogToSTDOUT("SingleGeneQuery(" + str(database.dbname) + ", " + str(gene) + ")") self.database = database self.gene = gene # "gene_index" gives the integer index used in the representation self.gene_index = self.database.network.index(self.gene) # num_gene_param is the size of the factor graph associated with "gene" self.num_gene_param = database.indexing_place_bases[self.gene_index] # num_reduced_param is the product of the sizes of all remaining factor graphs, and reorderings of all genes (including "gene") self.num_reduced_param = database.parametergraph.size( ) // self.num_gene_param # Create factor graph # TODO: The following algorithm for creating a factor graph takes O(NM^2) time, where N is length of hexcodes and M is size of factorgraph. # An O(NM) algorithm is possible (based on looping through codewords and trying out each promotion, using a hash table) # Implement this. self.hexcodes = self.database.parametergraph.factorgraph( self.gene_index) vertices = set(range(0, len(self.hexcodes))) edges = [(gpi1, gpi2) for gpi1 in vertices for gpi2 in vertices if isAdjacentHexcode(self.hexcodes[gpi1], self.hexcodes[gpi2]) ] self.graph = Graph(vertices, edges) LogToSTDOUT("SingleGeneQuery: FactorGraph generated") if not hasattr(database, 'SingleGeneQuery'): LogToSTDOUT( "SingleGeneQuery: SingleGeneQuery attribute missing from python database object." ) database.SingleGeneQuery = set() # For single-gene manipulations, we convert from parameter index to (reduced parameter index, gene parameter index) # To recover the parameter index from the reduced parameter index, we insert a "digit": database.full_parameter_index = lambda rpi, gpi, gene_index: rpi % database.indexing_place_values[ gene_index] + gpi * database.indexing_place_values[ gene_index] + (rpi // database.indexing_place_values[ gene_index]) * database.indexing_place_values[ gene_index + 1] database.reduced_parameter_index = lambda pi, gene_index: ( pi % database.indexing_place_values[gene_index] + (pi // database.indexing_place_values[gene_index + 1] ) * database.indexing_place_values[gene_index], (pi // database.indexing_place_values[gene_index] ) % database.indexing_place_bases[gene_index]) LogToSTDOUT("SingleGeneQuery: SingleGeneQuery attributes created.") if gene not in database.SingleGeneQuery: LogToSTDOUT( "SingleGeneQuery: database structure unaware of gene " + str(gene)) # Sanitize "gene": if gene not in database.names: raise NameError(gene + " is not the name of a node in the network") LogToSTDOUT("SingleGeneQuery: sanitized " + str(gene)) # Now we scan the database and create a new table we can do single gene poset queries with c = database.conn.cursor() # c.execute("drop table if exists " + gene) # gene is sanitized # Check if table exists LogToSTDOUT("SingleGeneQuery: cursor constructed ") c.execute( "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='" + gene + "';") LogToSTDOUT("SingleGeneQuery: checked for table") table_exists = c.fetchone()[0] if not table_exists: LogToSTDOUT("SingleGeneQuery: table did not exist") c.execute( "create table " + gene + " (ReducedParameterIndex INTEGER, GeneParameterIndex INTEGER, ParameterIndex INTEGER, MorseGraphIndex INTEGER)" ) LogToSTDOUT("SingleGeneQuery: created table") # # old method -- loads whole table into memory # values = [ self.reduced_parameter_index(row[0], self.gene_index) + row for row in c.execute("select * from Signatures")] # c.executemany('INSERT INTO ' + gene + ' VALUES (?,?,?,?)', values ) # new method -- a generator that uses fetchmany to keep memory usage down # default value arraysize=10000 was chosen based on limited testing. No improvement seen at 50000 or 100000 on a 13M parameter db. Worse performance at arraysize=1000. def valuegenerator(cursor, arraysize=10000): while True: rows = cursor.fetchmany(arraysize) if not rows: break yield [ database.reduced_parameter_index( row[0], self.gene_index) + row for row in rows ] c2 = database.conn.cursor( ) # need a second cursor to keep the place in the iteration as updates to the table occur c2.execute("select * from Signatures") LogToSTDOUT( "SingleGeneQuery: executed select statement on signatures") for values in valuegenerator(c2): c.executemany('INSERT INTO ' + gene + ' VALUES (?,?,?,?)', values) LogToSTDOUT("SingleGeneQuery: inserted values") c2.close() LogToSTDOUT("SingleGeneQuery: closed cursor") c.execute('create index ' + gene + '1 on ' + gene + ' (ReducedParameterIndex, GeneParameterIndex)' ) # gene is sanitized LogToSTDOUT("SingleGeneQuery: created index") database.conn.commit() LogToSTDOUT("SingleGeneQuery: committed database transaction") database.SingleGeneQuery.add(gene) LogToSTDOUT( "SingleGeneQuery: added gene to python database object.") LogToSTDOUT("SingleGeneQuery: constructed")
def __init__(self, database, bounds): LogToSTDOUT("MonostableFixedPointQuery :: initializing") self.set_of_matches = SingleFixedPointQuery(database,bounds).matches() & MonostableQuery(database).matches() LogToSTDOUT("MonostableFixedPointQuery :: constructed")