Instruction:
Write a Python 3 script to
remove nodes with the given function and namespace.

Response:
def remove_nodes_by_function_namespace(graph: BELGraph, func: str, namespace: Strings) -> None:
    """Remove nodes with the given function and namespace.

    This might be useful to exclude information learned about distant species, such as excluding all information
    from MGI and RGD in diseases where mice and rats don't give much insight to the human disease mechanism.
    """
    remove_filtered_nodes(graph, function_namespace_inclusion_builder(func, namespace))


Instruction:
Can you generate the documentation for the following Python 3 function
def preprocessing_br_projection_excel(path: str) -> pd.DataFrame:
    if not os.path.exists(path):
        raise ValueError("Error: %s file not found" % path)

    return pd.read_excel(path, sheetname=0, header=0)

Response: Preprocess the excel file.


Instruction:
Here you have a function in Python 3, explain what it does
def get_nift_values() -> Mapping[str, str]:
    r = get_bel_resource(NIFT)
    return {
        name.lower(): name
        for name in r['Values']
    }

Response: Extract the list of NIFT names from the BEL resource and build a dictionary mapping from the lowercased version to uppercase version.


Instruction:
How would you explain what the following Python 3 function does
def write_neurommsig_bel(file,
                         df: pd.DataFrame,
                         disease: str,
                         nift_values: Mapping[str, str],
                         ):
    """Writes the NeuroMMSigDB excel sheet to BEL

    :param file: a file or file-like that can be writen to
    :param df:
    :param disease:
    :param nift_values: a dictionary of lowercased to normal names in NIFT
    """
    write_neurommsig_biolerplate(disease, file)

    missing_features = set()
    fixed_caps = set()
    nift_value_originals = set(nift_values.values())

    graph = BELGraph(
        name=f'NeuroMMSigDB for {disease}',
        description=f'SNP and Clinical Features for Subgraphs in {disease}',
        authors='Daniel Domingo-Fernández, Charles Tapley Hoyt, Mufassra Naz, Aybuge Altay, Anandhi Iyappan',
        contact='daniel.domingo.fernandez@scai.fraunhofer.de',
        version=time.strftime('%Y%m%d'),
    )

    for pathway, pathway_df in df.groupby(pathway_column):
        sorted_pathway_df = pathway_df.sort_values(genes_column)
        sliced_df = sorted_pathway_df[columns].itertuples()

        for _, gene, pubmeds, lit_snps, gwas_snps, ld_block_snps, clinical_features, clinical_snps in sliced_df:
            gene = ensure_quotes(gene)

            for snp in itt.chain(lit_snps or [], gwas_snps or [], ld_block_snps or [], clinical_snps or []):
                if not snp.strip():
                    continue
                graph.add_association(
                    Gene('HGNC', gene),
                    Gene('DBSNP', snp),
                    evidence='Serialized from NeuroMMSigDB',
                    citation='28651363',
                    annotations={
                        'MeSHDisease': disease,
                    },
                )

            for clinical_feature in clinical_features or []:
                if not clinical_feature.strip():
                    continue

                if clinical_feature.lower() not in nift_values:
                    missing_features.add(clinical_feature)
                    continue

                if clinical_feature not in nift_value_originals:
                    fixed_caps.add((clinical_feature, nift_values[clinical_feature.lower()]))
                    clinical_feature = nift_values[clinical_feature.lower()]  # fix capitalization

                graph.add_association(
                    Gene('HGNC', gene),
                    Abundance('NIFT', clinical_feature),
                    evidence='Serialized from NeuroMMSigDB',
                    citation='28651363',
                    annotations={
                        'MeSHDisease': disease,
                    },
                )

                if clinical_snps:
                    for clinical_snp in clinical_snps:
                        graph.add_association(
                            Gene('DBSNP', clinical_snp),
                            Abundance('NIFT', clinical_feature),
                            evidence='Serialized from NeuroMMSigDB',
                            citation='28651363',
                            annotations={
                                'MeSHDisease': disease,
                            },
                        )

    if missing_features:
        log.warning('Missing Features in %s', disease)
        for feature in missing_features:
            log.warning(feature)

    if fixed_caps:
        log.warning('Fixed capitalization')
        for broken, fixed in fixed_caps:
            log.warning('%s -> %s', broken, fixed)

Response: Writes the NeuroMMSigDB excel sheet to file.


Instruction:
Here you have a function in Python 3, explain what it does
def get_contradiction_summary(graph: BELGraph) -> Iterable[Tuple[BaseEntity, BaseEntity, str]]:
    for u, v in set(graph.edges()):
        relations = {data[RELATION] for data in graph[u][v].values()}
        if relation_set_has_contradictions(relations):
            yield u, v, relations

Response: Yields triplets of source node target node and set of relations that have multiple contradictory relations.


Instruction:
Make a summary of the following Python 3 code
def get_regulatory_pairs(graph: BELGraph) -> Set[NodePair]:
    cg = get_causal_subgraph(graph)

    results = set()

    for u, v, d in cg.edges(data=True):
        if d[RELATION] not in CAUSAL_INCREASE_RELATIONS:
            continue

        if cg.has_edge(v, u) and any(dd[RELATION] in CAUSAL_DECREASE_RELATIONS for dd in cg[v][u].values()):
            results.add((u, v))

    return results

Response: Find pairs of nodes that have mutual causal edges that are regulating each other such that A - | B - | A.


Instruction:
How would you explain what the following Python 3 function does
def get_chaotic_pairs(graph: BELGraph) -> SetOfNodePairs:
    cg = get_causal_subgraph(graph)

    results = set()

    for u, v, d in cg.edges(data=True):
        if d[RELATION] not in CAUSAL_INCREASE_RELATIONS:
            continue

        if cg.has_edge(v, u) and any(dd[RELATION] in CAUSAL_INCREASE_RELATIONS for dd in cg[v][u].values()):
            results.add(tuple(sorted([u, v], key=str)))

    return results

Response: Find pairs of nodes that have mutual causal edges that are increasing each other such that A - > B and B - > A.


Instruction:
Make a summary of the following Python 3 code
def get_correlation_graph(graph: BELGraph) -> Graph:
    result = Graph()

    for u, v, d in graph.edges(data=True):
        if d[RELATION] not in CORRELATIVE_RELATIONS:
            continue

        if not result.has_edge(u, v):
            result.add_edge(u, v, **{d[RELATION]: True})

        elif d[RELATION] not in result[u][v]:
            log.log(5, 'broken correlation relation for %s, %s', u, v)
            result[u][v][d[RELATION]] = True
            result[v][u][d[RELATION]] = True

    return result

Response: Extract an undirected graph of only correlative relationships.


Instruction:
Create a Python 3 function for
returning a set of all the correlation triangles pointed by the given node.

Response:
def get_correlation_triangles(graph: BELGraph) -> SetOfNodeTriples:
    """Return a set of all triangles pointed by the given node."""
    return {
        tuple(sorted([n, u, v], key=str))
        for n in graph
        for u, v in itt.combinations(graph[n], 2)
        if graph.has_edge(u, v)
    }


Instruction:
Write a Python 3 script for
getting a set of triples representing the 3 - cycle nodes in a directional graph.

Response:
def get_triangles(graph: DiGraph) -> SetOfNodeTriples:
    """Get a set of triples representing the 3-cycles from a directional graph.

    Each 3-cycle is returned once, with nodes in sorted order.
    """
    return {
        tuple(sorted([a, b, c], key=str))
        for a, b in graph.edges()
        for c in graph.successors(b)
        if graph.has_edge(c, a)
    }


Instruction:
Write a Python 3 script for
yielding all unstable correlation triples in a given graph.

Response:
def get_separate_unstable_correlation_triples(graph: BELGraph) -> Iterable[NodeTriple]:
    """Yield all triples of nodes A, B, C such that ``A pos B``, ``A pos C``, and ``B neg C``.

    :return: An iterator over triples of unstable graphs, where the second two are negative
    """
    cg = get_correlation_graph(graph)

    for a, b, c in get_correlation_triangles(cg):
        if POSITIVE_CORRELATION in cg[a][b] and POSITIVE_CORRELATION in cg[b][c] and NEGATIVE_CORRELATION in \
                cg[a][c]:
            yield b, a, c
        if POSITIVE_CORRELATION in cg[a][b] and NEGATIVE_CORRELATION in cg[b][c] and POSITIVE_CORRELATION in \
                cg[a][c]:
            yield a, b, c
        if NEGATIVE_CORRELATION in cg[a][b] and POSITIVE_CORRELATION in cg[b][c] and POSITIVE_CORRELATION in \
                cg[a][c]:
            yield c, a, b


Instruction:
Can you implement a function in Python 3 that
yields all non - negative non - negative non - negative correlation triples in the graph.

Response:
def get_mutually_unstable_correlation_triples(graph: BELGraph) -> Iterable[NodeTriple]:
    """Yield triples of nodes (A, B, C) such that ``A neg B``, ``B neg C``, and ``C neg A``."""
    cg = get_correlation_graph(graph)

    for a, b, c in get_correlation_triangles(cg):
        if all(NEGATIVE_CORRELATION in x for x in (cg[a][b], cg[b][c], cg[a][c])):
            yield a, b, c


Instruction:
Create a Python 3 function for
applying Jens transformation to the graph.

Response:
def jens_transformation_alpha(graph: BELGraph) -> DiGraph:
    """Apply Jens' transformation (Type 1) to the graph.

    1. Induce a sub-graph over causal + correlative edges
    2. Transform edges by the following rules:
        - increases => increases
        - decreases => backwards increases
        - positive correlation => two way increases
        - negative correlation => delete

    The resulting graph can be used to search for 3-cycles, which now symbolize unstable triplets where ``A -> B``,
    ``A -| C`` and ``B positiveCorrelation C``.
    """
    result = DiGraph()

    for u, v, d in graph.edges(data=True):
        relation = d[RELATION]

        if relation == POSITIVE_CORRELATION:
            result.add_edge(u, v)
            result.add_edge(v, u)

        elif relation in CAUSAL_INCREASE_RELATIONS:
            result.add_edge(u, v)

        elif relation in CAUSAL_DECREASE_RELATIONS:
            result.add_edge(v, u)

    return result


Instruction:
Implement a function in Python 3 to
apply Jens - Correlation transformation to the graph.

Response:
def jens_transformation_beta(graph: BELGraph) -> DiGraph:
    """Apply Jens' Transformation (Type 2) to the graph.

    1. Induce a sub-graph over causal and correlative relations
    2. Transform edges with the following rules:
        - increases => backwards decreases
        - decreases => decreases
        - positive correlation => delete
        - negative correlation => two way decreases

    The resulting graph can be used to search for 3-cycles, which now symbolize stable triples where ``A -> B``,
    ``A -| C`` and ``B negativeCorrelation C``.
    """
    result = DiGraph()

    for u, v, d in graph.edges(data=True):
        relation = d[RELATION]

        if relation == NEGATIVE_CORRELATION:
            result.add_edge(u, v)
            result.add_edge(v, u)

        elif relation in CAUSAL_INCREASE_RELATIONS:
            result.add_edge(v, u)

        elif relation in CAUSAL_DECREASE_RELATIONS:
            result.add_edge(u, v)

    return result


Instruction:
Here you have a function in Python 3, explain what it does
def get_jens_unstable(graph: BELGraph) -> Iterable[NodeTriple]:
    r = jens_transformation_alpha(graph)
    return get_triangles(r)

Response: Returns an iterable of nodes that are not in Jens unstable state.


Instruction:
Explain what the following Python 3 code does
def summarize_stability(graph: BELGraph) -> Mapping[str, int]:
    regulatory_pairs = get_regulatory_pairs(graph)
    chaotic_pairs = get_chaotic_pairs(graph)
    dampened_pairs = get_dampened_pairs(graph)
    contraditory_pairs = get_contradiction_summary(graph)
    separately_unstable_triples = get_separate_unstable_correlation_triples(graph)
    mutually_unstable_triples = get_mutually_unstable_correlation_triples(graph)
    jens_unstable_triples = get_jens_unstable(graph)
    increase_mismatch_triples = get_increase_mismatch_triplets(graph)
    decrease_mismatch_triples = get_decrease_mismatch_triplets(graph)
    chaotic_triples = get_chaotic_triplets(graph)
    dampened_triples = get_dampened_triplets(graph)

    return {
        'Regulatory Pairs': _count_or_len(regulatory_pairs),
        'Chaotic Pairs': _count_or_len(chaotic_pairs),
        'Dampened Pairs': _count_or_len(dampened_pairs),
        'Contradictory Pairs': _count_or_len(contraditory_pairs),
        'Separately Unstable Triples': _count_or_len(separately_unstable_triples),
        'Mutually Unstable Triples': _count_or_len(mutually_unstable_triples),
        'Jens Unstable Triples': _count_or_len(jens_unstable_triples),
        'Increase Mismatch Triples': _count_or_len(increase_mismatch_triples),
        'Decrease Mismatch Triples': _count_or_len(decrease_mismatch_triples),
        'Chaotic Triples': _count_or_len(chaotic_triples),
        'Dampened Triples': _count_or_len(dampened_triples)
    }

Response: Summarize the stability of the graph.


Instruction:
Can you write a function in Python 3 where it
flattens the complex or composite abundance.

Response:
def flatten_list_abundance(node: ListAbundance) -> ListAbundance:
    """Flattens the complex or composite abundance."""
    return node.__class__(list(chain.from_iterable(
        (
            flatten_list_abundance(member).members
            if isinstance(member, ListAbundance) else
            [member]
        )
        for member in node.members
    )))


Instruction:
How would you code a function in Python 3 to
expand all list abundances to simple subject - predicate - object networks.

Response:
def list_abundance_cartesian_expansion(graph: BELGraph) -> None:
    """Expand all list abundances to simple subject-predicate-object networks."""
    for u, v, k, d in list(graph.edges(keys=True, data=True)):
        if CITATION not in d:
            continue

        if isinstance(u, ListAbundance) and isinstance(v, ListAbundance):
            for u_member, v_member in itt.product(u.members, v.members):
                graph.add_qualified_edge(
                    u_member, v_member,
                    relation=d[RELATION],
                    citation=d.get(CITATION),
                    evidence=d.get(EVIDENCE),
                    annotations=d.get(ANNOTATIONS),
                )

        elif isinstance(u, ListAbundance):
            for member in u.members:
                graph.add_qualified_edge(
                    member, v,
                    relation=d[RELATION],
                    citation=d.get(CITATION),
                    evidence=d.get(EVIDENCE),
                    annotations=d.get(ANNOTATIONS),
                )

        elif isinstance(v, ListAbundance):
            for member in v.members:
                graph.add_qualified_edge(
                    u, member,
                    relation=d[RELATION],
                    citation=d.get(CITATION),
                    evidence=d.get(EVIDENCE),
                    annotations=d.get(ANNOTATIONS),
                )

    _remove_list_abundance_nodes(graph)


Instruction:
Explain what the following Python 3 code does
def _reaction_cartesion_expansion_unqualified_helper(
        graph: BELGraph,
        u: BaseEntity,
        v: BaseEntity,
        d: dict,
) -> None:
    """Helper to deal with cartension expansion in unqualified edges."""
    if isinstance(u, Reaction) and isinstance(v, Reaction):
        enzymes = _get_catalysts_in_reaction(u) | _get_catalysts_in_reaction(v)

        for reactant, product in chain(itt.product(u.reactants, u.products),
                                       itt.product(v.reactants, v.products)):
            if reactant in enzymes or product in enzymes:
                continue

            graph.add_unqualified_edge(
                reactant, product, INCREASES
            )
        for product, reactant in itt.product(u.products, u.reactants):

            if reactant in enzymes or product in enzymes:
                continue

            graph.add_unqualified_edge(
                product, reactant, d[RELATION],
            )

    elif isinstance(u, Reaction):

        enzymes = _get_catalysts_in_reaction(u)

        for product in u.products:

            # Skip create increases edges between enzymes
            if product in enzymes:
                continue

            # Only add edge between v and reaction if the node is not part of the reaction
            # In practice skips hasReactant, hasProduct edges
            if v not in u.products and v not in u.reactants:
                graph.add_unqualified_edge(
                    product, v, INCREASES
                )
            for reactant in u.reactants:
                graph.add_unqualified_edge(
                    reactant, product, INCREASES
                )

    elif isinstance(v, Reaction):

        enzymes = _get_catalysts_in_reaction(v)

        for reactant in v.reactants:

            # Skip create increases edges between enzymes
            if reactant in enzymes:
                continue

            # Only add edge between v and reaction if the node is not part of the reaction
            # In practice skips hasReactant, hasProduct edges
            if u not in v.products and u not in v.reactants:
                graph.add_unqualified_edge(
                    u, reactant, INCREASES
                )
            for product in v.products:
                graph.add_unqualified_edge(
                    reactant, product, INCREASES
                )

Response: Helper to deal with cartension expansion in unqualified edges.


Instruction:
How would you implement a function in Python 3 that
returns nodes that are both in reactants and reactions in a reaction.

Response:
def _get_catalysts_in_reaction(reaction: Reaction) -> Set[BaseAbundance]:
    """Return nodes that are both in reactants and reactions in a reaction."""
    return {
        reactant
        for reactant in reaction.reactants
        if reactant in reaction.products
    }


Instruction:
How would you explain what the following Python 3 function does
def reaction_cartesian_expansion(graph: BELGraph, accept_unqualified_edges: bool = True) -> None:
    for u, v, d in list(graph.edges(data=True)):
        # Deal with unqualified edges
        if CITATION not in d and accept_unqualified_edges:
            _reaction_cartesion_expansion_unqualified_helper(graph, u, v, d)
            continue

        if isinstance(u, Reaction) and isinstance(v, Reaction):
            catalysts = _get_catalysts_in_reaction(u) | _get_catalysts_in_reaction(v)

            for reactant, product in chain(itt.product(u.reactants, u.products), itt.product(v.reactants, v.products)):
                if reactant in catalysts or product in catalysts:
                    continue
                graph.add_increases(
                    reactant, product,
                    citation=d.get(CITATION),
                    evidence=d.get(EVIDENCE),
                    annotations=d.get(ANNOTATIONS),
                )

            for product, reactant in itt.product(u.products, u.reactants):
                if reactant in catalysts or product in catalysts:
                    continue

                graph.add_qualified_edge(
                    product, reactant,
                    relation=d[RELATION],
                    citation=d.get(CITATION),
                    evidence=d.get(EVIDENCE),
                    annotations=d.get(ANNOTATIONS),
                )

        elif isinstance(u, Reaction):
            catalysts = _get_catalysts_in_reaction(u)

            for product in u.products:
                # Skip create increases edges between enzymes
                if product in catalysts:
                    continue

                # Only add edge between v and reaction if the node is not part of the reaction
                # In practice skips hasReactant, hasProduct edges
                if v not in u.products and v not in u.reactants:
                    graph.add_increases(
                        product, v,
                        citation=d.get(CITATION),
                        evidence=d.get(EVIDENCE),
                        annotations=d.get(ANNOTATIONS),
                    )

                for reactant in u.reactants:
                    graph.add_increases(
                        reactant, product,
                        citation=d.get(CITATION),
                        evidence=d.get(EVIDENCE),
                        annotations=d.get(ANNOTATIONS),
                    )

        elif isinstance(v, Reaction):
            for reactant in v.reactants:
                catalysts = _get_catalysts_in_reaction(v)

                # Skip create increases edges between enzymes
                if reactant in catalysts:
                    continue

                # Only add edge between v and reaction if the node is not part of the reaction
                # In practice skips hasReactant, hasProduct edges
                if u not in v.products and u not in v.reactants:
                    graph.add_increases(
                        u, reactant,
                        citation=d.get(CITATION),
                        evidence=d.get(EVIDENCE),
                        annotations=d.get(ANNOTATIONS),
                    )
                for product in v.products:
                    graph.add_increases(
                        reactant, product,
                        citation=d.get(CITATION),
                        evidence=d.get(EVIDENCE),
                        annotations=d.get(ANNOTATIONS),
                    )

    _remove_reaction_nodes(graph)

Response: Expand all reactions to simple subject - predicate - object networks.


Instruction:
Can you tell what is the following Python 3 function doing
def insert_graph(self, graph: BELGraph, **_kwargs) -> Network:
        result = _Namespace()
        result.id = len(self.networks)

        self.networks[result.id] = graph

        return result

Response: Insert a graph and return the resulting ORM object.


Instruction:
Write a Python 3 function for
getting several graphs by their identifiers.

Response:
def get_graphs_by_ids(self, network_ids: Iterable[int]) -> List[BELGraph]:
        """Get several graphs by their identifiers."""
        return [
            self.networks[network_id]
            for network_id in network_ids
        ]


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _generate_citation_dict(graph: BELGraph) -> Mapping[str, Mapping[Tuple[BaseEntity, BaseEntity], str]]:
    results = defaultdict(lambda: defaultdict(set))

    for u, v, data in graph.edges(data=True):
        if CITATION not in data:
            continue
        results[data[CITATION][CITATION_TYPE]][u, v].add(data[CITATION][CITATION_REFERENCE].strip())

    return dict(results)

Response: Prepare a citation data dictionary from a graph.


Instruction:
Explain what the following Python 3 code does
def get_pmid_by_keyword(keyword: str,
                        graph: Optional[BELGraph] = None,
                        pubmed_identifiers: Optional[Set[str]] = None,
                        ) -> Set[str]:
    """Get the set of PubMed identifiers beginning with the given keyword string.

    :param keyword: The beginning of a PubMed identifier
    :param graph: A BEL graph
    :param pubmed_identifiers: A set of pre-cached PubMed identifiers
    :return: A set of PubMed identifiers starting with the given string
    """
    if pubmed_identifiers is not None:
        return {
            pubmed_identifier
            for pubmed_identifier in pubmed_identifiers
            if pubmed_identifier.startswith(keyword)
        }

    if graph is None:
        raise ValueError('Graph not supplied')

    return {
        pubmed_identifier
        for pubmed_identifier in iterate_pubmed_identifiers(graph)
        if pubmed_identifier.startswith(keyword)
    }

Response: Get the set of PubMed identifiers starting with the given keyword string.


Instruction:
Can you tell what is the following Python 3 function doing
def count_citations(graph: BELGraph, **annotations) -> Counter:
    citations = defaultdict(set)

    annotation_dict_filter = build_edge_data_filter(annotations)

    for u, v, _, d in filter_edges(graph, annotation_dict_filter):
        if CITATION not in d:
            continue

        citations[u, v].add((d[CITATION][CITATION_TYPE], d[CITATION][CITATION_REFERENCE].strip()))

    return Counter(itt.chain.from_iterable(citations.values()))

Response: Counts the citations in a given graph based on a given set of annotations.


Instruction:
Create a Python 3 function for
grouping the citation counters by subgraphs induced by the annotation.

Response:
def count_citations_by_annotation(graph: BELGraph, annotation: str) -> Mapping[str, typing.Counter[str]]:
    """Group the citation counters by subgraphs induced by the annotation.

    :param graph: A BEL graph
    :param annotation: The annotation to use to group the graph
    :return: A dictionary of Counters {subgraph name: Counter from {citation: frequency}}
    """
    citations = defaultdict(lambda: defaultdict(set))
    for u, v, data in graph.edges(data=True):
        if not edge_has_annotation(data, annotation) or CITATION not in data:
            continue

        k = data[ANNOTATIONS][annotation]

        citations[k][u, v].add((data[CITATION][CITATION_TYPE], data[CITATION][CITATION_REFERENCE].strip()))

    return {k: Counter(itt.chain.from_iterable(v.values())) for k, v in citations.items()}


Instruction:
Explain what the following Python 3 code does
def count_author_publications(graph: BELGraph) -> typing.Counter[str]:
    authors = group_as_dict(_iter_author_publiations(graph))
    return Counter(count_dict_values(count_defaultdict(authors)))

Response: Count the number of publications of each author to the given graph.


Instruction:
Can you create a Python 3 function that
gets the set of authors that are a substring of the given keyword.

Response:
def get_authors_by_keyword(keyword: str, graph=None, authors=None) -> Set[str]:
    """Get authors for whom the search term is a substring.

    :param pybel.BELGraph graph: A BEL graph
    :param keyword: The keyword to search the author strings for
    :param set[str] authors: An optional set of pre-cached authors calculated from the graph
    :return: A set of authors with the keyword as a substring
    """
    keyword_lower = keyword.lower()

    if authors is not None:
        return {
            author
            for author in authors
            if keyword_lower in author.lower()
        }

    if graph is None:
        raise ValueError('Graph not supplied')

    return {
        author
        for author in get_authors(graph)
        if keyword_lower in author.lower()
    }


Instruction:
Implement a function in Python 3 to
group the author counters by sub - graphs induced by the annotation.

Response:
def count_authors_by_annotation(graph: BELGraph, annotation: str = 'Subgraph') -> Mapping[str, typing.Counter[str]]:
    """Group the author counters by sub-graphs induced by the annotation.

    :param graph: A BEL graph
    :param annotation: The annotation to use to group the graph
    :return: A dictionary of Counters {subgraph name: Counter from {author: frequency}}
    """
    authors = group_as_dict(_iter_authors_by_annotation(graph, annotation=annotation))
    return count_defaultdict(authors)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_evidences_by_pmid(graph: BELGraph, pmids: Union[str, Iterable[str]]):
    result = defaultdict(set)

    for _, _, _, data in filter_edges(graph, build_pmid_inclusion_filter(pmids)):
        result[data[CITATION][CITATION_REFERENCE]].add(data[EVIDENCE])

    return dict(result)

Response:
Get a dictionary from the given PubMed identifiers to the sets of all evidence strings associated with each
   .


Instruction:
Create a Python 3 function to
count the number of citations from each year.

Response:
def count_citation_years(graph: BELGraph) -> typing.Counter[int]:
    """Count the number of citations from each year."""
    result = defaultdict(set)

    for _, _, data in graph.edges(data=True):
        if CITATION not in data or CITATION_DATE not in data[CITATION]:
            continue

        try:
            dt = _ensure_datetime(data[CITATION][CITATION_DATE])
            result[dt.year].add((data[CITATION][CITATION_TYPE], data[CITATION][CITATION_REFERENCE]))
        except Exception:
            continue

    return count_dict_values(result)


Instruction:
Implement a function in Python 3 to
create a citation timeline from the graph.

Response:
def get_citation_years(graph: BELGraph) -> List[Tuple[int, int]]:
    """Create a citation timeline counter from the graph."""
    return create_timeline(count_citation_years(graph))


Instruction:
Implement a function in Python 3 to
complete the Counter timeline.

Response:
def create_timeline(year_counter: typing.Counter[int]) -> List[Tuple[int, int]]:
    """Complete the Counter timeline.

    :param Counter year_counter: counter dict for each year
    :return: complete timeline
    """
    if not year_counter:
        return []

    from_year = min(year_counter) - 1
    until_year = datetime.now().year + 1

    return [
        (year, year_counter.get(year, 0))
        for year in range(from_year, until_year)
    ]


Instruction:
How would you implement a function in Python 3 that
counts the confidences in the graph.

Response:
def count_confidences(graph: BELGraph) -> typing.Counter[str]:
    """Count the confidences in the graph."""
    return Counter(
        (
            'None'
            if ANNOTATIONS not in data or 'Confidence' not in data[ANNOTATIONS] else
            list(data[ANNOTATIONS]['Confidence'])[0]
        )
        for _, _, data in graph.edges(data=True)
        if CITATION in data  # don't bother with unqualified statements
    )


Instruction:
Implement a function in Python 3 to
overwrite all PubMed citations with values from NCBI s eUtils lookup service.

Response:
def enrich_pubmed_citations(graph: BELGraph, manager: Manager) -> Set[str]:
    """Overwrite all PubMed citations with values from NCBI's eUtils lookup service.

    :return: A set of PMIDs for which the eUtils service crashed
    """
    pmids = get_pubmed_identifiers(graph)
    pmid_data, errors = get_citations_by_pmids(manager=manager, pmids=pmids)

    for u, v, k in filter_edges(graph, has_pubmed):
        pmid = graph[u][v][k][CITATION][CITATION_REFERENCE].strip()

        if pmid not in pmid_data:
            log.warning('Missing data for PubMed identifier: %s', pmid)
            errors.add(pmid)
            continue

        graph[u][v][k][CITATION].update(pmid_data[pmid])

    return errors


Instruction:
Implement a Python 3 function for
updating the context of a subgraph from the universe of all knowledge.

Response:
def update_context(universe: BELGraph, graph: BELGraph):
    """Update the context of a subgraph from the universe of all knowledge."""
    for namespace in get_namespaces(graph):
        if namespace in universe.namespace_url:
            graph.namespace_url[namespace] = universe.namespace_url[namespace]
        elif namespace in universe.namespace_pattern:
            graph.namespace_pattern[namespace] = universe.namespace_pattern[namespace]
        else:
            log.warning('namespace: %s missing from universe', namespace)

    for annotation in get_annotations(graph):
        if annotation in universe.annotation_url:
            graph.annotation_url[annotation] = universe.annotation_url[annotation]
        elif annotation in universe.annotation_pattern:
            graph.annotation_pattern[annotation] = universe.annotation_pattern[annotation]
        elif annotation in universe.annotation_list:
            graph.annotation_list[annotation] = universe.annotation_list[annotation]
        else:
            log.warning('annotation: %s missing from universe', annotation)


Instruction:
Given the following Python 3 function, write the documentation
def highlight_nodes(graph: BELGraph, nodes: Optional[Iterable[BaseEntity]] = None, color: Optional[str]=None):
    color = color or NODE_HIGHLIGHT_DEFAULT_COLOR
    for node in nodes if nodes is not None else graph:
        graph.node[node][NODE_HIGHLIGHT] = color

Response: Adds a highlight tag to the given nodes.


Instruction:
Can you create a Python 3 function that
returns if the given node is highlighted.

Response:
def is_node_highlighted(graph: BELGraph, node: BaseEntity) -> bool:
    """Returns if the given node is highlighted.

    :param graph: A BEL graph
    :param node: A BEL node
    :type node: tuple
    :return: Does the node contain highlight information?
    :rtype: bool
    """
    return NODE_HIGHLIGHT in graph.node[node]


Instruction:
Can you generate the documentation for the following Python 3 function
def remove_highlight_nodes(graph: BELGraph, nodes: Optional[Iterable[BaseEntity]]=None) -> None:
    for node in graph if nodes is None else nodes:
        if is_node_highlighted(graph, node):
            del graph.node[node][NODE_HIGHLIGHT]

Response: Removes the highlight from the given nodes if none given.


Instruction:
Create a Python 3 function for
adding a highlight tag to the given edges.

Response:
def highlight_edges(graph: BELGraph, edges=None, color: Optional[str]=None) -> None:
    """Adds a highlight tag to the given edges.

    :param graph: A BEL graph
    :param edges: The edges (4-tuples of u, v, k, d) to add a highlight tag on
    :type edges: iter[tuple]
    :param str color: The color to highlight (use something that works with CSS)
    """
    color = color or EDGE_HIGHLIGHT_DEFAULT_COLOR
    for u, v, k, d in edges if edges is not None else graph.edges(keys=True, data=True):
        graph[u][v][k][EDGE_HIGHLIGHT] = color


Instruction:
Can you tell what is the following Python 3 function doing
def is_edge_highlighted(graph: BELGraph, u, v, k) -> bool:
    return EDGE_HIGHLIGHT in graph[u][v][k]

Response: Returns True if the given edge is highlighted.


Instruction:
Here you have a function in Python 3, explain what it does
def remove_highlight_edges(graph: BELGraph, edges=None):
    for u, v, k, _ in graph.edges(keys=True, data=True) if edges is None else edges:
        if is_edge_highlighted(graph, u, v, k):
            del graph[u][v][k][EDGE_HIGHLIGHT]

Response: Removes the highlight from the given edges or all edges if none given.


Instruction:
How would you code a function in Python 3 to
highlight all nodes and edges in the given graph that are in the given universe.

Response:
def highlight_subgraph(universe: BELGraph, graph: BELGraph):
    """Highlight all nodes/edges in the universe that in the given graph.

    :param universe: The universe of knowledge
    :param graph: The BEL graph to mutate
    """
    highlight_nodes(universe, graph)
    highlight_edges(universe, graph.edges())


Instruction:
Make a summary of the following Python 3 code
def remove_highlight_subgraph(graph: BELGraph, subgraph: BELGraph):
    remove_highlight_nodes(graph, subgraph.nodes())
    remove_highlight_edges(graph, subgraph.edges())

Response: Remove the highlight from all nodes and edges in the subgraph.


Instruction:
Create a Python 3 function for
getting the out - edges to the given node that are causal.

Response:
def get_causal_out_edges(
        graph: BELGraph,
        nbunch: Union[BaseEntity, Iterable[BaseEntity]],
) -> Set[Tuple[BaseEntity, BaseEntity]]:
    """Get the out-edges to the given node that are causal.

    :return: A set of (source, target) pairs where the source is the given node
    """
    return {
        (u, v)
        for u, v, k, d in graph.out_edges(nbunch, keys=True, data=True)
        if is_causal_relation(graph, u, v, k, d)
    }


Instruction:
How would you code a function in Python 3 to
return a set of all nodes that have a causal origin from within the graph.

Response:
def get_causal_source_nodes(graph: BELGraph, func: str) -> Set[BaseEntity]:
    """Return a set of all nodes that have an in-degree of 0.

    This likely means that it is an external perturbagen and is not known to have any causal origin from within the
    biological system. These nodes are useful to identify because they generally don't provide any mechanistic insight.
    """
    return {
        node
        for node in graph
        if node.function == func and is_causal_source(graph, node)
    }


Instruction:
Create a Python 3 function for
returning a set of all nodes that are causal central.

Response:
def get_causal_central_nodes(graph: BELGraph, func: str) -> Set[BaseEntity]:
    """Return a set of all nodes that have both an in-degree > 0 and out-degree > 0.

    This means that they are an integral part of a pathway, since they are both produced and consumed.
    """
    return {
        node
        for node in graph
        if node.function == func and is_causal_central(graph, node)
    }


Instruction:
Make a summary of the following Python 3 code
def get_causal_sink_nodes(graph: BELGraph, func) -> Set[BaseEntity]:
    return {
        node
        for node in graph
        if node.function == func and is_causal_sink(graph, node)
    }

Response: Returns a set of all causal sink nodes that have a causal out - degree of 0.


Instruction:
Implement a function in Python 3 to
get the most common number of nodes in a graph.

Response:
def count_top_centrality(graph: BELGraph, number: Optional[int] = 30) -> Mapping[BaseEntity, int]:
    """Get top centrality dictionary."""
    dd = nx.betweenness_centrality(graph)
    dc = Counter(dd)
    return dict(dc.most_common(number))


Instruction:
How would you explain what the following Python 3 function does
def get_modifications_count(graph: BELGraph) -> Mapping[str, int]:
    return remove_falsy_values({
        'Translocations': len(get_translocated(graph)),
        'Degradations': len(get_degradations(graph)),
        'Molecular Activities': len(get_activities(graph)),
    })

Response: Get a modifications count dictionary.


Instruction:
Implement a Python 3 function for
removing all values that are zero.

Response:
def remove_falsy_values(counter: Mapping[Any, int]) -> Mapping[Any, int]:
    """Remove all values that are zero."""
    return {
        label: count
        for label, count in counter.items()
        if count
    }


Instruction:
Here you have a function in Python 3, explain what it does
def _collapse_variants_by_function(graph: BELGraph, func: str) -> None:
    for parent_node, variant_node, data in graph.edges(data=True):
        if data[RELATION] == HAS_VARIANT and parent_node.function == func:
            collapse_pair(graph, from_node=variant_node, to_node=parent_node)

Response: Collapse all of the given functions s variants to their parents in - place.


Instruction:
How would you code a function in Python 3 to
rewire all protein variants to Gene objects.

Response:
def rewire_variants_to_genes(graph: BELGraph) -> None:
    """Find all protein variants that are pointing to a gene and not a protein and fixes them by changing their
    function to be :data:`pybel.constants.GENE`, in place

    A use case is after running :func:`collapse_to_genes`.
    """
    mapping = {}

    for node in graph:
        if not isinstance(node, Protein) or not node.variants:
            continue

        mapping[node] = Gene(
            name=node.name,
            namespace=node.namespace,
            identifier=node.identifier,
            variants=node.variants,
        )

    nx.relabel_nodes(graph, mapping, copy=False)


Instruction:
Explain what the following Python 3 code does
def _collapse_edge_passing_predicates(graph: BELGraph, edge_predicates: EdgePredicates = None) -> None:
    for u, v, _ in filter_edges(graph, edge_predicates=edge_predicates):
        collapse_pair(graph, survivor=u, victim=v)

Response: Collapse all edges passing the given edge predicates.


Instruction:
How would you implement a function in Python 3 that
collapses pairs of nodes with the given namespaces that have the given relationship.

Response:
def _collapse_edge_by_namespace(graph: BELGraph,
                                victim_namespaces: Strings,
                                survivor_namespaces: str,
                                relations: Strings) -> None:
    """Collapse pairs of nodes with the given namespaces that have the given relationship.

    :param graph: A BEL Graph
    :param victim_namespaces: The namespace(s) of the node to collapse
    :param survivor_namespaces: The namespace of the node to keep
    :param relations: The relation(s) to search
    """
    relation_filter = build_relation_predicate(relations)
    source_namespace_filter = build_source_namespace_filter(victim_namespaces)
    target_namespace_filter = build_target_namespace_filter(survivor_namespaces)

    edge_predicates = [
        relation_filter,
        source_namespace_filter,
        target_namespace_filter
    ]

    _collapse_edge_passing_predicates(graph, edge_predicates=edge_predicates)


Instruction:
Here you have a function in Python 3, explain what it does
def collapse_equivalencies_by_namespace(graph: BELGraph, victim_namespace: Strings, survivor_namespace: str) -> None:
    _collapse_edge_by_namespace(graph, victim_namespace, survivor_namespace, EQUIVALENT_TO)

Response: Collapse pairs of nodes with the given namespaces that have equivalence relationships between them.


Instruction:
How would you code a function in Python 3 to
collapse nodes with the given namespaces that have orthology relationships.

Response:
def collapse_orthologies_by_namespace(graph: BELGraph, victim_namespace: Strings, survivor_namespace: str) -> None:
    """Collapse pairs of nodes with the given namespaces that have orthology relationships.

    :param graph: A BEL Graph
    :param victim_namespace: The namespace(s) of the node to collapse
    :param survivor_namespace: The namespace of the node to keep

    To collapse all MGI nodes to their HGNC orthologs, use:
    >>> collapse_orthologies_by_namespace('MGI', 'HGNC')

    To collapse collapse both MGI and RGD nodes to their HGNC orthologs, use:
    >>> collapse_orthologies_by_namespace(['MGI', 'RGD'], 'HGNC')
    """
    _collapse_edge_by_namespace(graph, victim_namespace, survivor_namespace, ORTHOLOGOUS)


Instruction:
Write a Python 3 function that can
collapse all equivalence edges away from Entrez. Assumes well formed 2 - way equivalencies.

Response:
def collapse_entrez_equivalencies(graph: BELGraph):
    """Collapse all equivalence edges away from Entrez. Assumes well formed, 2-way equivalencies."""
    relation_filter = build_relation_predicate(EQUIVALENT_TO)
    source_namespace_filter = build_source_namespace_filter(['EGID', 'EG', 'ENTREZ'])

    edge_predicates = [
        relation_filter,
        source_namespace_filter,
    ]

    _collapse_edge_passing_predicates(graph, edge_predicates=edge_predicates)


Instruction:
Implement a function in Python 3 to
collapse consistent edges together.

Response:
def collapse_consistent_edges(graph: BELGraph):
    """Collapse consistent edges together.

    .. warning:: This operation doesn't preserve evidences or other annotations
    """
    for u, v in graph.edges():
        relation = pair_is_consistent(graph, u, v)

        if not relation:
            continue

        edges = [(u, v, k) for k in graph[u][v]]
        graph.remove_edges_from(edges)
        graph.add_edge(u, v, attr_dict={RELATION: relation})


Instruction:
Can you tell what is the following Python 3 function doing
def collapse_to_protein_interactions(graph: BELGraph) -> BELGraph:
    rv: BELGraph = graph.copy()

    collapse_to_genes(rv)

    def is_edge_ppi(_: BELGraph, u: BaseEntity, v: BaseEntity, __: str) -> bool:
        """Check if an edge is a PPI."""
        return isinstance(u, Gene) and isinstance(v, Gene)

    return get_subgraph_by_edge_filter(rv, edge_predicates=[has_polarity, is_edge_ppi])

Response: Collapse a graph made of only causal gene and protein edges.


Instruction:
Implement a Python 3 function for
collapsing all nodes with the same name merging namespaces by picking first alphabetical one.

Response:
def collapse_nodes_with_same_names(graph: BELGraph) -> None:
    """Collapse all nodes with the same name, merging namespaces by picking first alphabetical one."""
    survivor_mapping = defaultdict(set) # Collapse mapping dict
    victims = set() # Things already mapped while iterating

    it = tqdm(itt.combinations(graph, r=2), total=graph.number_of_nodes() * (graph.number_of_nodes() - 1) / 2)
    for a, b in it:
        if b in victims:
            continue

        a_name, b_name = a.get(NAME), b.get(NAME)
        if not a_name or not b_name or a_name.lower() != b_name.lower():
            continue

        if a.keys() != b.keys():  # not same version (might have variants)
            continue

        # Ensure that the values in the keys are also the same
        for k in set(a.keys()) - {NAME, NAMESPACE}:
            if a[k] != b[k]:  # something different
                continue

        survivor_mapping[a].add(b)
        # Keep track of things that has been already mapped
        victims.add(b)

    collapse_nodes(graph, survivor_mapping)


Instruction:
Implement a Python 3 function for
outputting the HBP knowledge graph to the desktop

Response:
def main(output):
    """Output the HBP knowledge graph to the desktop"""
    from hbp_knowledge import get_graph
    graph = get_graph()
    text = to_html(graph)
    print(text, file=output)


Instruction:
Explain what the following Python 3 code does
def node_is_upstream_leaf(graph: BELGraph, node: BaseEntity) -> bool:
    return 0 == len(graph.predecessors(node)) and 1 == len(graph.successors(node))

Response: Return if the node is an upstream leaf.


Instruction:
Make a summary of the following Python 3 code
def get_unweighted_upstream_leaves(graph: BELGraph, key: Optional[str] = None) -> Iterable[BaseEntity]:
    if key is None:
        key = WEIGHT

    return filter_nodes(graph, [node_is_upstream_leaf, data_missing_key_builder(key)])

Response: Get unweighted upstream leaves.


Instruction:
Explain what the following Python 3 code does
def remove_unweighted_leaves(graph: BELGraph, key: Optional[str] = None) -> None:
    unweighted_leaves = list(get_unweighted_upstream_leaves(graph, key=key))
    graph.remove_nodes_from(unweighted_leaves)

Response: Removes nodes that are leaves and that don t have a weight attribute set.


Instruction:
Make a summary of the following Python 3 code
def is_unweighted_source(graph: BELGraph, node: BaseEntity, key: str) -> bool:
    return graph.in_degree(node) == 0 and key not in graph.nodes[node]

Response: Check if the node is both a source and also has an annotation.


Instruction:
Explain what the following Python 3 code does
def get_unweighted_sources(graph: BELGraph, key: Optional[str] = None) -> Iterable[BaseEntity]:
    if key is None:
        key = WEIGHT

    for node in graph:
        if is_unweighted_source(graph, node, key):
            yield node

Response: Get nodes that are unweighted and on the given key.


Instruction:
How would you implement a function in Python 3 that
prunes unannotated nodes on the periphery of the sub - graph.

Response:
def remove_unweighted_sources(graph: BELGraph, key: Optional[str] = None) -> None:
    """Prune unannotated nodes on the periphery of the sub-graph.

    :param graph: A BEL graph
    :param key: The key in the node data dictionary representing the experimental data. Defaults to
     :data:`pybel_tools.constants.WEIGHT`.
    """
    nodes = list(get_unweighted_sources(graph, key=key))
    graph.remove_nodes_from(nodes)


Instruction:
Here you have a function in Python 3, explain what it does
def prune_mechanism_by_data(graph, key: Optional[str] = None) -> None:
    remove_unweighted_leaves(graph, key=key)
    remove_unweighted_sources(graph, key=key)

Response: Removes all nodes that don t have weights.


Instruction:
Can you tell what is the following Python 3 function doing
def generate_mechanism(graph: BELGraph, node: BaseEntity, key: Optional[str] = None) -> BELGraph:
    subgraph = get_upstream_causal_subgraph(graph, node)
    expand_upstream_causal(graph, subgraph)
    remove_inconsistent_edges(subgraph)
    collapse_consistent_edges(subgraph)

    if key is not None:  # FIXME when is it not pruned?
        prune_mechanism_by_data(subgraph, key)

    return subgraph

Response: Generate a mechanistic sub - graph upstream of the given node.


Instruction:
Given the following Python 3 function, write the documentation
def generate_bioprocess_mechanisms(graph, key: Optional[str] = None) -> Mapping[BiologicalProcess, BELGraph]:
    return {
        biological_process: generate_mechanism(graph, biological_process, key=key)
        for biological_process in get_nodes_by_function(graph, BIOPROCESS)
    }

Response: Generate a mechanistic sub - graph for each biological process in the graph.


Instruction:
Create a Python 3 function to
return a dictionary mapping annotation value to a NeuroMMSig composite score.

Response:
def get_neurommsig_scores(graph: BELGraph,
                          genes: List[Gene],
                          annotation: str = 'Subgraph',
                          ora_weight: Optional[float] = None,
                          hub_weight: Optional[float] = None,
                          top_percent: Optional[float] = None,
                          topology_weight: Optional[float] = None,
                          preprocess: bool = False
                          ) -> Optional[Mapping[str, float]]:
    """Preprocess the graph, stratify by the given annotation, then run the NeuroMMSig algorithm on each.

    :param graph: A BEL graph
    :param genes: A list of gene nodes
    :param annotation: The annotation to use to stratify the graph to subgraphs
    :param ora_weight: The relative weight of the over-enrichment analysis score from
     :py:func:`neurommsig_gene_ora`. Defaults to 1.0.
    :param hub_weight: The relative weight of the hub analysis score from :py:func:`neurommsig_hubs`.
     Defaults to 1.0.
    :param top_percent: The percentage of top genes to use as hubs. Defaults to 5% (0.05).
    :param topology_weight: The relative weight of the topolgical analysis core from
     :py:func:`neurommsig_topology`. Defaults to 1.0.
    :param preprocess: If true, preprocess the graph.
    :return: A dictionary from {annotation value: NeuroMMSig composite score}

    Pre-processing steps:

    1. Infer the central dogma with :func:``
    2. Collapse all proteins, RNAs and miRNAs to genes with :func:``
    3. Collapse variants to genes with :func:``
    """
    if preprocess:
        graph = neurommsig_graph_preprocessor.run(graph)

    if not any(gene in graph for gene in genes):
        logger.debug('no genes mapping to graph')
        return

    subgraphs = get_subgraphs_by_annotation(graph, annotation=annotation)

    return get_neurommsig_scores_prestratified(
        subgraphs=subgraphs,
        genes=genes,
        ora_weight=ora_weight,
        hub_weight=hub_weight,
        top_percent=top_percent,
        topology_weight=topology_weight,
    )


Instruction:
Write a Python 3 script to
take a set of graphs and runs neurommsig on each node. Returns a dictionary of annotation values that are used to identify the nodes in the graph.

Response:
def get_neurommsig_scores_prestratified(subgraphs: Mapping[str, BELGraph],
                                        genes: List[Gene],
                                        ora_weight: Optional[float] = None,
                                        hub_weight: Optional[float] = None,
                                        top_percent: Optional[float] = None,
                                        topology_weight: Optional[float] = None,
                                        ) -> Optional[Mapping[str, float]]:
    """Takes a graph stratification and runs neurommsig on each

    :param subgraphs: A pre-stratified set of graphs
    :param genes: A list of gene nodes
    :param ora_weight: The relative weight of the over-enrichment analysis score from
     :py:func:`neurommsig_gene_ora`. Defaults to 1.0.
    :param hub_weight: The relative weight of the hub analysis score from :py:func:`neurommsig_hubs`.
     Defaults to 1.0.
    :param top_percent: The percentage of top genes to use as hubs. Defaults to 5% (0.05).
    :param topology_weight: The relative weight of the topolgical analysis core from
     :py:func:`neurommsig_topology`. Defaults to 1.0.
    :return: A dictionary from {annotation value: NeuroMMSig composite score}

    Pre-processing steps:

    1. Infer the central dogma with :func:``
    2. Collapse all proteins, RNAs and miRNAs to genes with :func:``
    3. Collapse variants to genes with :func:``
    """
    return {
        name: get_neurommsig_score(
            graph=subgraph,
            genes=genes,
            ora_weight=ora_weight,
            hub_weight=hub_weight,
            top_percent=top_percent,
            topology_weight=topology_weight,
        )
        for name, subgraph in subgraphs.items()
    }


Instruction:
Write a Python 3 script to
calculate the NeuroMMSig composite score for a given list of genes.

Response:
def get_neurommsig_score(graph: BELGraph,
                         genes: List[Gene],
                         ora_weight: Optional[float] = None,
                         hub_weight: Optional[float] = None,
                         top_percent: Optional[float] = None,
                         topology_weight: Optional[float] = None) -> float:
    """Calculate the composite NeuroMMSig Score for a given list of genes.

    :param graph: A BEL graph
    :param genes: A list of gene nodes
    :param ora_weight: The relative weight of the over-enrichment analysis score from
     :py:func:`neurommsig_gene_ora`. Defaults to 1.0.
    :param hub_weight: The relative weight of the hub analysis score from :py:func:`neurommsig_hubs`.
     Defaults to 1.0.
    :param top_percent: The percentage of top genes to use as hubs. Defaults to 5% (0.05).
    :param topology_weight: The relative weight of the topolgical analysis core from
     :py:func:`neurommsig_topology`. Defaults to 1.0.
    :return: The NeuroMMSig composite score
    """
    ora_weight = ora_weight or 1.0
    hub_weight = hub_weight or 1.0
    topology_weight = topology_weight or 1.0
    total_weight = ora_weight + hub_weight + topology_weight

    genes = list(genes)

    ora_score = neurommsig_gene_ora(graph, genes)
    hub_score = neurommsig_hubs(graph, genes, top_percent=top_percent)
    topology_score = neurommsig_topology(graph, genes)

    weighted_sum = (
            ora_weight * ora_score +
            hub_weight * hub_score +
            topology_weight * topology_score
    )

    return weighted_sum / total_weight


Instruction:
Implement a function in Python 3 to
calculate the percentage of target genes mappable to the graph.

Response:
def neurommsig_gene_ora(graph: BELGraph, genes: List[Gene]) -> float:
    """Calculate the percentage of target genes mappable to the graph.

    Assume: graph central dogma inferred, collapsed to genes, collapsed variants
    """
    graph_genes = set(get_nodes_by_function(graph, GENE))
    return len(graph_genes.intersection(genes)) / len(graph_genes)


Instruction:
Can you generate the documentation for the following Python 3 function
def neurommsig_hubs(graph: BELGraph, genes: List[Gene], top_percent: Optional[float] = None) -> float:
    top_percent = top_percent or 0.05

    if graph.number_of_nodes() < 20:
        logger.debug('Graph has less than 20 nodes')
        return 0.0

    graph_genes = set(get_nodes_by_function(graph, GENE))

    bc = Counter({
        node: betweenness_centrality
        for node, betweenness_centrality in calculate_betweenness_centality(graph).items()
        if node in graph_genes
    })

    # TODO consider continuous analog with weighting by percentile
    number_central_nodes = int(len(graph_genes) * top_percent)

    if number_central_nodes < 1:
        number_central_nodes = 1

    number_mappable_central_nodes = sum(
        node in genes
        for node in bc.most_common(number_central_nodes)
    )

    return number_mappable_central_nodes / number_central_nodes

Response: Calculate the percentage of target genes mappable to the graph.


Instruction:
Here you have a function in Python 3, explain what it does
def neurommsig_topology(graph: BELGraph, nodes: List[BaseEntity]) -> float:
    nodes = list(nodes)
    number_nodes = len(nodes)

    if number_nodes <= 1:
        # log.debug('')
        return 0.0

    unnormalized_sum = sum(
        u in graph[v]
        for u, v in itt.product(nodes, repeat=2)
        if v in graph and u != v
    )

    return unnormalized_sum / (number_nodes * (number_nodes - 1.0))

Response: Calculate the neighbor score for a given list of nodes.


Instruction:
Can you write a function in Python 3 where it
performs a single run over all microstates and return the canonical cluster statistics

Response:
def bond_run(perc_graph_result, seed, ps, convolution_factors_tasks):
    """
    Perform a single run (realization) over all microstates and return the
    canonical cluster statistics
    """
    microcanonical_statistics = percolate.hpc.bond_microcanonical_statistics(
        seed=seed, **perc_graph_result
    )

    # initialize statistics array
    canonical_statistics = np.empty(
        ps.size,
        dtype=percolate.hpc.canonical_statistics_dtype(
            spanning_cluster=SPANNING_CLUSTER,
        )
    )

    # loop over all p's and convolve canonical statistics
    # http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#modifying-array-values
    for row, convolution_factors_task in zip(
        np.nditer(canonical_statistics, op_flags=['writeonly']),
        convolution_factors_tasks,
    ):
        # load task result
        # http://jug.readthedocs.org/en/latest/api.html#jug.Task.load
        assert not convolution_factors_task.is_loaded()
        convolution_factors_task.load()
        # fetch task result
        my_convolution_factors = convolution_factors_task.result

        # convolve to canonical statistics
        row[...] = percolate.hpc.bond_canonical_statistics(
            microcanonical_statistics=microcanonical_statistics,
            convolution_factors=my_convolution_factors,
            spanning_cluster=SPANNING_CLUSTER,
        )
        # explicitly unload task to save memory
        # http://jug.readthedocs.org/en/latest/api.html#jug.Task.unload
        convolution_factors_task.unload()

    # initialize canonical averages for reduce
    ret = percolate.hpc.bond_initialize_canonical_averages(
        canonical_statistics=canonical_statistics,
        spanning_cluster=SPANNING_CLUSTER,
    )

    return ret


Instruction:
How would you code a function in Python 3 to
perform a number of runs The number of runs is the number of seeds convolution_factors_tasks_iterator needs to be an iterator We shield the convolution factors tasks from jug value/result mechanism by supplying an iterator to the list of tasks for lazy evaluation http://github.com/luispedro/jug/blob/43f0d80a78f418fd3aa2b8705eaf7c4a5175fff7/jug/task.py#L100 http://github.com/luispedro/jug/blob/43f0d80a78f418fd3aa2b8705eaf7c4a5175fff7/jug/task.py#L455

Response:
def bond_task(
    perc_graph_result, seeds, ps, convolution_factors_tasks_iterator
):
    """
    Perform a number of runs

    The number of runs is the number of seeds

    convolution_factors_tasks_iterator needs to be an iterator

    We shield the convolution factors tasks from jug value/result mechanism
    by supplying an iterator to the list of tasks for lazy evaluation
    http://github.com/luispedro/jug/blob/43f0d80a78f418fd3aa2b8705eaf7c4a5175fff7/jug/task.py#L100
    http://github.com/luispedro/jug/blob/43f0d80a78f418fd3aa2b8705eaf7c4a5175fff7/jug/task.py#L455
    """

    # restore the list of convolution factors tasks
    convolution_factors_tasks = list(convolution_factors_tasks_iterator)

    return reduce(
        percolate.hpc.bond_reduce,
        map(
            bond_run,
            itertools.repeat(perc_graph_result),
            seeds,
            itertools.repeat(ps),
            itertools.repeat(convolution_factors_tasks),
        )
    )


Instruction:
Create a Python 3 function for
returning an iterable over all nodes in a BEL graph with only a connection to one node. Useful for gene and anomaly.

Response:
def get_leaves_by_type(graph, func=None, prune_threshold=1):
    """Returns an iterable over all nodes in graph (in-place) with only a connection to one node. Useful for gene and
     RNA. Allows for optional filter by function type.

    :param pybel.BELGraph graph: A BEL graph
    :param func: If set, filters by the node's function from :mod:`pybel.constants` like
                    :data:`pybel.constants.GENE`, :data:`pybel.constants.RNA`,  :data:`pybel.constants.PROTEIN`, or
                    :data:`pybel.constants.BIOPROCESS`
    :type func: str
    :param prune_threshold: Removes nodes with less than or equal to this number of connections. Defaults to :code:`1`
    :type prune_threshold: int
    :return: An iterable over nodes with only a connection to one node
    :rtype: iter[tuple]
    """
    for node, data in graph.nodes(data=True):
        if func and func != data.get(FUNCTION):
            continue

        if graph.in_degree(node) + graph.out_degree(node) <= prune_threshold:
            yield node


Instruction:
Can you create a Python 3 function that
gets the set of possible successor edges peripheral to the sub - graph.

Response:
def get_peripheral_successor_edges(graph: BELGraph, subgraph: BELGraph) -> EdgeIterator:
    """Get the set of possible successor edges peripheral to the sub-graph.

    The source nodes in this iterable are all inside the sub-graph, while the targets are outside.
    """
    for u in subgraph:
        for _, v, k in graph.out_edges(u, keys=True):
            if v not in subgraph:
                yield u, v, k


Instruction:
Can you write a function in Python 3 where it
gets the set of possible predecessor edges peripheral to the sub - graph.

Response:
def get_peripheral_predecessor_edges(graph: BELGraph, subgraph: BELGraph) -> EdgeIterator:
    """Get the set of possible predecessor edges peripheral to the sub-graph.

    The target nodes in this iterable are all inside the sub-graph, while the sources are outside.
    """
    for v in subgraph:
        for u, _, k in graph.in_edges(v, keys=True):
            if u not in subgraph:
                yield u, v, k


Instruction:
Make a summary of the following Python 3 code
def count_sources(edge_iter: EdgeIterator) -> Counter:
    return Counter(u for u, _, _ in edge_iter)

Response: Count the source nodes in an edge iterator with keys and data.


Instruction:
Implement a Python 3 function for
counting the target nodes in an edge iterator with keys and data.

Response:
def count_targets(edge_iter: EdgeIterator) -> Counter:
    """Count the target nodes in an edge iterator with keys and data.

    :return: A counter of target nodes in the iterable
    """
    return Counter(v for _, v, _ in edge_iter)


Instruction:
Create a Python 3 function to
return an iterable of all edges from a given subgraph whose source and target nodes pass all of the given filters .

Response:
def get_subgraph_edges(graph: BELGraph,
                       annotation: str,
                       value: str,
                       source_filter=None,
                       target_filter=None,
                       ):
    """Gets all edges from a given subgraph whose source and target nodes pass all of the given filters

    :param pybel.BELGraph graph: A BEL graph
    :param str annotation:  The annotation to search
    :param str value: The annotation value to search by
    :param source_filter: Optional filter for source nodes (graph, node) -> bool
    :param target_filter: Optional filter for target nodes (graph, node) -> bool
    :return: An iterable of (source node, target node, key, data) for all edges that match the annotation/value and
             node filters
    :rtype: iter[tuple]
    """
    if source_filter is None:
        source_filter = keep_node_permissive

    if target_filter is None:
        target_filter = keep_node_permissive

    for u, v, k, data in graph.edges(keys=True, data=True):
        if not edge_has_annotation(data, annotation):
            continue
        if data[ANNOTATIONS][annotation] == value and source_filter(graph, u) and target_filter(graph, v):
            yield u, v, k, data


Instruction:
Write a Python 3 script for
getting a summary dictionary of all peripheral nodes to a given sub - graph.

Response:
def get_subgraph_peripheral_nodes(graph: BELGraph,
                                  subgraph: Iterable[BaseEntity],
                                  node_predicates: NodePredicates = None,
                                  edge_predicates: EdgePredicates = None,
                                  ):
    """Get a summary dictionary of all peripheral nodes to a given sub-graph.

    :return: A dictionary of {external node: {'successor': {internal node: list of (key, dict)},
                                            'predecessor': {internal node: list of (key, dict)}}}
    :rtype: dict

    For example, it might be useful to quantify the number of predecessors and successors:

    >>> from pybel.struct.filters import exclude_pathology_filter
    >>> value = 'Blood vessel dilation subgraph'
    >>> sg = get_subgraph_by_annotation_value(graph, annotation='Subgraph', value=value)
    >>> p = get_subgraph_peripheral_nodes(graph, sg, node_predicates=exclude_pathology_filter)
    >>> for node in sorted(p, key=lambda n: len(set(p[n]['successor']) | set(p[n]['predecessor'])), reverse=True):
    >>>     if 1 == len(p[value][node]['successor']) or 1 == len(p[value][node]['predecessor']):
    >>>         continue
    >>>     print(node,
    >>>           len(p[node]['successor']),
    >>>           len(p[node]['predecessor']),
    >>>           len(set(p[node]['successor']) | set(p[node]['predecessor'])))
    """
    node_filter = concatenate_node_predicates(node_predicates=node_predicates)
    edge_filter = and_edge_predicates(edge_predicates=edge_predicates)

    result = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))

    for u, v, k, d in get_peripheral_successor_edges(graph, subgraph):
        if not node_filter(graph, v) or not node_filter(graph, u) or not edge_filter(graph, u, v, k):
            continue
        result[v]['predecessor'][u].append((k, d))

    for u, v, k, d in get_peripheral_predecessor_edges(graph, subgraph):
        if not node_filter(graph, v) or not node_filter(graph, u) or not edge_filter(graph, u, v, k):
            continue
        result[u]['successor'][v].append((k, d))

    return result


Instruction:
How would you code a function in Python 3 to
iterate over all possible edges, peripheral to a given subgraph, that could be added from the given graph. Edges could be added if they go to nodes that are involved in relationships that occur with more than the threshold (default 2) number of nodes in the subgraph. :param universe: The universe of BEL knowledge :param graph: The (sub)graph to expand :param threshold: Minimum frequency of betweenness occurrence to add a gap node A reasonable edge filter to use is :func:`pybel_tools.filters.keep_causal_edges` because this function can allow for huge expansions if there happen to be hub nodes.

Response:
def expand_periphery(universe: BELGraph,
                     graph: BELGraph,
                     node_predicates: NodePredicates = None,
                     edge_predicates: EdgePredicates = None,
                     threshold: int = 2,
                     ) -> None:
    """Iterates over all possible edges, peripheral to a given subgraph, that could be added from the given graph.
    Edges could be added if they go to nodes that are involved in relationships that occur with more than the
    threshold (default 2) number of nodes in the subgraph.

    :param universe: The universe of BEL knowledge
    :param graph: The (sub)graph to expand
    :param threshold: Minimum frequency of betweenness occurrence to add a gap node

    A reasonable edge filter to use is :func:`pybel_tools.filters.keep_causal_edges` because this function can allow
    for huge expansions if there happen to be hub nodes.
    """
    nd = get_subgraph_peripheral_nodes(universe, graph, node_predicates=node_predicates,
                                       edge_predicates=edge_predicates)

    for node, dd in nd.items():
        pred_d = dd['predecessor']
        succ_d = dd['successor']

        in_subgraph_connections = set(pred_d) | set(succ_d)

        if threshold > len(in_subgraph_connections):
            continue

        graph.add_node(node, attr_dict=universe[node])

        for u, edges in pred_d.items():
            for k, d in edges:
                safe_add_edge(graph, u, node, k, d)

        for v, edges in succ_d.items():
            for k, d in edges:
                safe_add_edge(graph, node, v, k, d)


Instruction:
Create a Python 3 function for
adding all of the members of the complex abundances to the graph.

Response:
def enrich_complexes(graph: BELGraph) -> None:
    """Add all of the members of the complex abundances to the graph."""
    nodes = list(get_nodes_by_function(graph, COMPLEX))
    for u in nodes:
        for v in u.members:
            graph.add_has_component(u, v)


Instruction:
Write a Python 3 function that can
enrich the composite abundances in the graph with the members of the composite abundances.

Response:
def enrich_composites(graph: BELGraph):
    """Adds all of the members of the composite abundances to the graph."""
    nodes = list(get_nodes_by_function(graph, COMPOSITE))
    for u in nodes:
        for v in u.members:
            graph.add_has_component(u, v)


Instruction:
Can you write a function in Python 3 where it
adds all of the reactants and products of reactions to the graph.

Response:
def enrich_reactions(graph: BELGraph):
    """Adds all of the reactants and products of reactions to the graph."""
    nodes = list(get_nodes_by_function(graph, REACTION))
    for u in nodes:
        for v in u.reactants:
            graph.add_has_reactant(u, v)

        for v in u.products:
            graph.add_has_product(u, v)


Instruction:
Here you have a function in Python 3, explain what it does
def enrich_variants(graph: BELGraph, func: Union[None, str, Iterable[str]] = None):
    if func is None:
        func = {PROTEIN, RNA, MIRNA, GENE}

    nodes = list(get_nodes_by_function(graph, func))
    for u in nodes:
        parent = u.get_parent()

        if parent is None:
            continue

        if parent not in graph:
            graph.add_has_variant(parent, u)

Response: Add the reference nodes for all variants of the given function to the given graph.


Instruction:
Write a Python 3 function for
enriching the sub - graph with the unqualified edges from the graph.

Response:
def enrich_unqualified(graph: BELGraph):
    """Enrich the sub-graph with the unqualified edges from the graph.

    The reason you might want to do this is you induce a sub-graph from the original graph based on an annotation
    filter, but the unqualified edges that don't have annotations that most likely connect elements within your graph
    are not included.

    .. seealso::

        This function thinly wraps the successive application of the following functions:

        - :func:`enrich_complexes`
        - :func:`enrich_composites`
        - :func:`enrich_reactions`
        - :func:`enrich_variants`

    Equivalent to:

    >>> enrich_complexes(graph)
    >>> enrich_composites(graph)
    >>> enrich_reactions(graph)
    >>> enrich_variants(graph)
    """
    enrich_complexes(graph)
    enrich_composites(graph)
    enrich_reactions(graph)
    enrich_variants(graph)


Instruction:
How would you explain what the following Python 3 function does
def expand_internal(universe: BELGraph, graph: BELGraph, edge_predicates: EdgePredicates = None) -> None:
    edge_filter = and_edge_predicates(edge_predicates)

    for u, v in itt.product(graph, repeat=2):
        if graph.has_edge(u, v) or not universe.has_edge(u, v):
            continue

        rs = defaultdict(list)
        for key, data in universe[u][v].items():
            if not edge_filter(universe, u, v, key):
                continue

            rs[data[RELATION]].append((key, data))

        if 1 == len(rs):
            relation = list(rs)[0]
            for key, data in rs[relation]:
                graph.add_edge(u, v, key=key, **data)
        else:
            log.debug('Multiple relationship types found between %s and %s', u, v)

Response: Expand the internal information of the given universe.


Instruction:
Here you have a function in Python 3, explain what it does
def expand_internal_causal(universe: BELGraph, graph: BELGraph) -> None:
    expand_internal(universe, graph, edge_predicates=is_causal_relation)

Response: Add causal edges between entities in the sub - graph.


Instruction:
How would you implement a function in Python 3 that
returns the set of all namespaces with incorrect names in the graph.

Response:
def get_namespaces_with_incorrect_names(graph: BELGraph) -> Set[str]:
    """Return the set of all namespaces with incorrect names in the graph."""
    return {
        exc.namespace
        for _, exc, _ in graph.warnings
        if isinstance(exc, (MissingNamespaceNameWarning, MissingNamespaceRegexWarning))
    }


Instruction:
Make a summary of the following Python 3 code
def get_undefined_namespaces(graph: BELGraph) -> Set[str]:
    return {
        exc.namespace
        for _, exc, _ in graph.warnings
        if isinstance(exc, UndefinedNamespaceWarning)
    }

Response: Get all namespaces that are not actually defined in the BEL graph.


Instruction:
Implement a function in Python 3 to
return the set of all incorrect names from the given namespace in the graph.

Response:
def get_incorrect_names_by_namespace(graph: BELGraph, namespace: str) -> Set[str]:
    """Return the set of all incorrect names from the given namespace in the graph.

    :return: The set of all incorrect names from the given namespace in the graph
    """
    return {
        exc.name
        for _, exc, _ in graph.warnings
        if isinstance(exc, (MissingNamespaceNameWarning, MissingNamespaceRegexWarning)) and exc.namespace == namespace
    }


Instruction:
Can you create a Python 3 function that
gets the names from a namespace that was not actually defined.

Response:
def get_undefined_namespace_names(graph: BELGraph, namespace: str) -> Set[str]:
    """Get the names from a namespace that wasn't actually defined.

    :return: The set of all names from the undefined namespace
    """
    return {
        exc.name
        for _, exc, _ in graph.warnings
        if isinstance(exc, UndefinedNamespaceWarning) and exc.namespace == namespace
    }


Instruction:
Can you generate the documentation for the following Python 3 function
def get_incorrect_names(graph: BELGraph) -> Mapping[str, Set[str]]:
    return {
        namespace: get_incorrect_names_by_namespace(graph, namespace)
        for namespace in get_namespaces(graph)
    }

Response: Return the dict of all incorrect names from the given namespace in the graph.


Instruction:
How would you explain what the following Python 3 function does
def get_undefined_annotations(graph: BELGraph) -> Set[str]:
    return {
        exc.annotation
        for _, exc, _ in graph.warnings
        if isinstance(exc, UndefinedAnnotationWarning)
    }

Response: Get all undefined annotations that aren t actually defined in the graph.


Instruction:
Implement a function in Python 3 to
group all of the incorrect identifiers in a dictionary of namespace to list of erroneous names.

Response:
def calculate_incorrect_name_dict(graph: BELGraph) -> Mapping[str, str]:
    """Group all of the incorrect identifiers in a dict of {namespace: list of erroneous names}.

    :return: A dictionary of {namespace: list of erroneous names}
    """
    missing = defaultdict(list)

    for _, e, ctx in graph.warnings:
        if not isinstance(e, (MissingNamespaceNameWarning, MissingNamespaceRegexWarning)):
            continue
        missing[e.namespace].append(e.name)

    return dict(missing)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def group_errors(graph: BELGraph) -> Mapping[str, List[int]]:
    warning_summary = defaultdict(list)

    for _, exc, _ in graph.warnings:
        warning_summary[str(exc)].append(exc.line_number)

    return dict(warning_summary)

Response: Group the errors together for analysis of the most frequent error.


Instruction:
Can you write a function in Python 3 where it
gets the n most common errors in a graph.

Response:
def get_most_common_errors(graph: BELGraph, n: Optional[int] = 20):
    """Get the (n) most common errors in a graph."""
    return count_dict_values(group_errors(graph)).most_common(n)


Instruction:
Create a Python 3 function for
taking the names from the graph in a given namespace and returns them together

Response:
def get_names_including_errors_by_namespace(graph: BELGraph, namespace: str) -> Set[str]:
    """Takes the names from the graph in a given namespace (:func:`pybel.struct.summary.get_names_by_namespace`) and
    the erroneous names from the same namespace (:func:`get_incorrect_names_by_namespace`) and returns them together
    as a unioned set

    :return: The set of all correct and incorrect names from the given namespace in the graph
    """
    return get_names_by_namespace(graph, namespace) | get_incorrect_names_by_namespace(graph, namespace)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_names_including_errors(graph: BELGraph) -> Mapping[str, Set[str]]:
    return {
        namespace: get_names_including_errors_by_namespace(graph, namespace)
        for namespace in get_namespaces(graph)
    }

Response: Takes the names from the graph in a given namespace and returns the set of all correct and incorrect names in the given namespace.


Instruction:
Create a Python 3 function for
iterating over pairs in list s -> s0 s1 s2 s3...

Response:
def pairwise(iterable: Iterable[X]) -> Iterable[Tuple[X, X]]:
    """Iterate over pairs in list s -> (s0,s1), (s1,s2), (s2, s3), ..."""
    a, b = itt.tee(iterable)
    next(b, None)
    return zip(a, b)


Instruction:
How would you code a function in Python 3 to
count the number of elements in each value of the dictionary.

Response:
def count_defaultdict(dict_of_lists: Mapping[X, List[Y]]) -> Mapping[X, typing.Counter[Y]]:
    """Count the number of elements in each value of the dictionary."""
    return {
        k: Counter(v)
        for k, v in dict_of_lists.items()
    }


Instruction:
Can you implement a function in Python 3 that
counts the number of elements in each value in a dictionary.

Response:
def count_dict_values(dict_of_counters: Mapping[X, Sized]) -> typing.Counter[X]:
    """Count the number of elements in each value (can be list, Counter, etc).

    :param dict_of_counters: A dictionary of things whose lengths can be measured (lists, Counters, dicts)
    :return: A Counter with the same keys as the input but the count of the length of the values list/tuple/set/Counter
    """
    return Counter({
        k: len(v)
        for k, v in dict_of_counters.items()
    })


Instruction:
Explain what the following Python 3 code does
def set_percentage(x: Iterable[X], y: Iterable[X]) -> float:
    a, b = set(x), set(y)

    if not a:
        return 0.0

    return len(a & b) / len(a)

Response: Calculates the percentage of the elements in x contained within y.


Instruction:
Write a Python 3 script for
calculating the tanimoto set similarity.

Response:
def tanimoto_set_similarity(x: Iterable[X], y: Iterable[X]) -> float:
    """Calculate the tanimoto set similarity."""
    a, b = set(x), set(y)
    union = a | b

    if not union:
        return 0.0

    return len(a & b) / len(union)


Instruction:
Explain what the following Python 3 code does
def min_tanimoto_set_similarity(x: Iterable[X], y: Iterable[X]) -> float:
    a, b = set(x), set(y)

    if not a or not b:
        return 0.0

    return len(a & b) / min(len(a), len(b))

Response: Calculate the similarity between two sets of tanimoto sets.


Instruction:
Given the following Python 3 function, write the documentation
def calculate_single_tanimoto_set_distances(target: Iterable[X], dict_of_sets: Mapping[Y, Set[X]]) -> Mapping[Y, float]:
    target_set = set(target)

    return {
        k: tanimoto_set_similarity(target_set, s)
        for k, s in dict_of_sets.items()
    }

Response: Calculates the similarity between the target set and the set in the given dict of sets.


Instruction:
Can you tell what is the following Python 3 function doing
def calculate_tanimoto_set_distances(dict_of_sets: Mapping[X, Set]) -> Mapping[X, Mapping[X, float]]:
    result: Dict[X, Dict[X, float]] = defaultdict(dict)

    for x, y in itt.combinations(dict_of_sets, 2):
        result[x][y] = result[y][x] = tanimoto_set_similarity(dict_of_sets[x], dict_of_sets[y])

    for x in dict_of_sets:
        result[x][x] = 1.0

    return dict(result)

Response: Calculates the distance matrix for each set in the given dict.


Instruction:
How would you explain what the following Python 3 function does
def safe_add_edge(graph, u, v, key, attr_dict, **attr):
    if key < 0:
        graph.add_edge(u, v, key=key, attr_dict=attr_dict, **attr)
    else:
        graph.add_edge(u, v, attr_dict=attr_dict, **attr)

Response: Adds an edge while preserving negative keys and paying no respect to positive ones.


Instruction:
Implement a function in Python 3 to
prepare a C3 bar chart from a Counter

Response:
def prepare_c3(data: Union[List[Tuple[str, int]], Mapping[str, int]],
               y_axis_label: str = 'y',
               x_axis_label: str = 'x',
               ) -> str:
    """Prepares C3 JSON for making a bar chart from a Counter

    :param data: A dictionary of {str: int} to display as bar chart
    :param y_axis_label: The Y axis label
    :param x_axis_label: X axis internal label. Should be left as default 'x')
    :return: A JSON dictionary for making a C3 bar chart
    """
    if not isinstance(data, list):
        data = sorted(data.items(), key=itemgetter(1), reverse=True)

    try:
        labels, values = zip(*data)
    except ValueError:
        log.info(f'no values found for {x_axis_label}, {y_axis_label}')
        labels, values = [], []

    return json.dumps([
        [x_axis_label] + list(labels),
        [y_axis_label] + list(values),
    ])


Instruction:
Can you write a function in Python 3 where it
prepares C3 JSON string dump for a time series.

Response:
def prepare_c3_time_series(data: List[Tuple[int, int]], y_axis_label: str = 'y', x_axis_label: str = 'x') -> str:
    """Prepare C3 JSON string dump for a time series.

    :param data: A list of tuples [(year, count)]
    :param y_axis_label: The Y axis label
    :param x_axis_label: X axis internal label. Should be left as default 'x')
    """
    years, counter = zip(*data)

    years = [
        datetime.date(year, 1, 1).isoformat()
        for year in years
    ]

    return json.dumps([
        [x_axis_label] + list(years),
        [y_axis_label] + list(counter)
    ])


Instruction:
Write a Python 3 function that can
calculate the betweenness centrality over nodes in the graph.

Response:
def calculate_betweenness_centality(graph: BELGraph, number_samples: int = CENTRALITY_SAMPLES) -> Counter:
    """Calculate the betweenness centrality over nodes in the graph.

    Tries to do it with a certain number of samples, but then tries a complete approach if it fails.
    """
    try:
        res = nx.betweenness_centrality(graph, k=number_samples)
    except Exception:
        res = nx.betweenness_centrality(graph)
    return Counter(res)


Instruction:
Create a Python 3 function to
iterate over all possible circulations of an ordered collection.

Response:
def get_circulations(elements: T) -> Iterable[T]:
    """Iterate over all possible circulations of an ordered collection (tuple or list).

    Example:

    >>> list(get_circulations([1, 2, 3]))
    [[1, 2, 3], [2, 3, 1], [3, 1, 2]]
    """
    for i in range(len(elements)):
        yield elements[i:] + elements[:i]


Instruction:
Write a Python 3 function for
getting a canonical representation of the ordered collection by finding its minimum circulation with the given sort key.

Response:
def canonical_circulation(elements: T, key: Optional[Callable[[T], bool]] = None) -> T:
    """Get get a canonical representation of the ordered collection by finding its minimum circulation with the
    given sort key
    """
    return min(get_circulations(elements), key=key)


Instruction:
Can you tell what is the following Python 3 function doing
def pair_has_contradiction(graph: BELGraph, u: BaseEntity, v: BaseEntity) -> bool:
    relations = {data[RELATION] for data in graph[u][v].values()}
    return relation_set_has_contradictions(relations)

Response: Check if a pair of nodes has any contradictions in their causal relationships.


Instruction:
Implement a Python 3 function for
returning if the set of BEL relations contains a contradiction.

Response:
def relation_set_has_contradictions(relations: Set[str]) -> bool:
    """Return if the set of BEL relations contains a contradiction."""
    has_increases = any(relation in CAUSAL_INCREASE_RELATIONS for relation in relations)
    has_decreases = any(relation in CAUSAL_DECREASE_RELATIONS for relation in relations)
    has_cnc = any(relation == CAUSES_NO_CHANGE for relation in relations)
    return 1 < sum([has_cnc, has_decreases, has_increases])


Instruction:
Can you create a Python 3 function that
prepares the (internal) percolation graph from a given graph Helper function to prepare the given graph for spanning cluster detection (if required). Basically it strips off the auxiliary nodes and edges again. It also returns fundamental graph quantitities (number of nodes and edges). Parameters ---------- graph spanning_cluster Returns ------- ret : tuple

Response:
def percolation_graph(graph, spanning_cluster=True):
    """
    Prepare the (internal) percolation graph from a given graph

    Helper function to prepare the given graph for spanning cluster detection
    (if required).
    Basically it strips off the auxiliary nodes and edges again.
    It also returns fundamental graph quantitities (number of nodes and edges).

    Parameters
    ----------
    graph
    spanning_cluster

    Returns
    -------
    ret : tuple

    """
    ret = dict()

    ret['graph'] = graph
    ret['spanning_cluster'] = bool(spanning_cluster)

    # initialize percolation graph
    if spanning_cluster:
        spanning_auxiliary_node_attributes = nx.get_node_attributes(
            graph, 'span'
        )
        ret['auxiliary_node_attributes'] = spanning_auxiliary_node_attributes
        auxiliary_nodes = spanning_auxiliary_node_attributes.keys()
        if not list(auxiliary_nodes):
            raise ValueError(
                'Spanning cluster is to be detected, but no auxiliary nodes '
                'given.'
            )

        spanning_sides = list(set(spanning_auxiliary_node_attributes.values()))
        if len(spanning_sides) != 2:
            raise ValueError(
                'Spanning cluster is to be detected, but auxiliary nodes '
                'of less or more than 2 types (sides) given.'
            )

        ret['spanning_sides'] = spanning_sides
        ret['auxiliary_edge_attributes'] = nx.get_edge_attributes(
            graph, 'span'
        )

    # get subgraph on which percolation is to take place (strip off the
    # auxiliary nodes)
    if spanning_cluster:
        perc_graph = graph.subgraph(
            [
                node for node in graph.nodes_iter()
                if 'span' not in graph.node[node]
            ]
        )
    else:
        perc_graph = graph

    ret['perc_graph'] = perc_graph

    # number of nodes N
    ret['num_nodes'] = nx.number_of_nodes(perc_graph)

    # number of edges M
    ret['num_edges'] = nx.number_of_edges(perc_graph)

    return ret


Instruction:
Can you generate the documentation for the following Python 3 function
def sample_states(
    graph, spanning_cluster=True, model='bond', copy_result=True
):
    '''
    Generate successive sample states of the percolation model

    This is a :ref:`generator function <python:tut-generators>` to successively
    add one edge at a time from the graph to the percolation model.
    At each iteration, it calculates and returns the cluster statistics.

    Parameters
    ----------
    graph : networkx.Graph
        The substrate graph on which percolation is to take place

    spanning_cluster : bool, optional
        Whether to detect a spanning cluster or not.
        Defaults to ``True``.

    model : str, optional
        The percolation model (either ``'bond'`` or ``'site'``).
        Defaults to ``'bond'``.

        .. note:: Other models than ``'bond'`` are not supported yet.

    copy_result : bool, optional
        Whether to return a copy or a reference to the result dictionary.
        Defaults to ``True``.

    Yields
    ------
    ret : dict
        Cluster statistics

    ret['n'] : int
        Number of occupied bonds

    ret['N'] : int
        Total number of sites

    ret['M'] : int
        Total number of bonds

    ret['has_spanning_cluster'] : bool
        ``True`` if there is a spanning cluster, ``False`` otherwise.
        Only exists if `spanning_cluster` argument is set to ``True``.

    ret['max_cluster_size'] : int
        Size of the largest cluster (absolute number of sites)

    ret['moments'] : 1-D :py:class:`numpy.ndarray` of int
        Array of size ``5``.
        The ``k``-th entry is the ``k``-th raw moment of the (absolute) cluster
        size distribution, with ``k`` ranging from ``0`` to ``4``.

    Raises
    ------
    ValueError
        If `model` does not equal ``'bond'``.

    ValueError
        If `spanning_cluster` is ``True``, but `graph` does not contain any
        auxiliary nodes to detect spanning clusters.

    See also
    --------

    microcanonical_averages : Evolves multiple sample states in parallel

    Notes
    -----
    Iterating through this generator is a single run of the Newman-Ziff
    algorithm. [2]_
    The first iteration yields the trivial state with :math:`n = 0` occupied
    bonds.

    Spanning cluster

        In order to detect a spanning cluster, `graph` needs to contain
        auxiliary nodes and edges, cf. Reference [2]_, Figure 6.
        The auxiliary nodes and edges have the ``'span'`` `attribute
        <http://networkx.github.io/documentation/latest/tutorial/tutorial.html#node-attributes>`_.
        The value is either ``0`` or ``1``, distinguishing the two sides of the
        graph to span.

    Raw moments of the cluster size distribution

        The :math:`k`-th raw moment of the (absolute) cluster size distribution
        is :math:`\sum_s' s^k N_s`, where :math:`s` is the cluster size and
        :math:`N_s` is the number of clusters of size :math:`s`. [3]_
        The primed sum :math:`\sum'` signifies that the largest cluster is
        excluded from the sum. [4]_

    References
    ----------
    .. [2] Newman, M. E. J. & Ziff, R. M. Fast monte carlo algorithm for site
        or bond percolation. Physical Review E 64, 016706+ (2001),
        `doi:10.1103/physreve.64.016706 <http://dx.doi.org/10.1103/physreve.64.016706>`_.

    .. [3] Stauffer, D. & Aharony, A. Introduction to Percolation Theory (Taylor &
       Francis, London, 1994), second edn.

    .. [4] Binder, K. & Heermann, D. W. Monte Carlo Simulation in Statistical
       Physics (Springer, Berlin, Heidelberg, 2010),
       `doi:10.1007/978-3-642-03163-2 <http://dx.doi.org/10.1007/978-3-642-03163-2>`_.
    '''

    if model != 'bond':
        raise ValueError('Only bond percolation supported.')

    if spanning_cluster:
        auxiliary_node_attributes = nx.get_node_attributes(graph, 'span')
        auxiliary_nodes = auxiliary_node_attributes.keys()
        if not list(auxiliary_nodes):
            raise ValueError(
                'Spanning cluster is to be detected, but no auxiliary nodes '
                'given.'
            )

        spanning_sides = list(set(auxiliary_node_attributes.values()))
        if len(spanning_sides) != 2:
            raise ValueError(
                'Spanning cluster is to be detected, but auxiliary nodes '
                'of less or more than 2 types (sides) given.'
            )

        auxiliary_edge_attributes = nx.get_edge_attributes(graph, 'span')

    # get subgraph on which percolation is to take place (strip off the
    # auxiliary nodes)
    if spanning_cluster:
        perc_graph = graph.subgraph(
            [
                node for node in graph.nodes_iter()
                if 'span' not in graph.node[node]
            ]
        )
    else:
        perc_graph = graph

    # get a list of edges for easy access in later iterations
    perc_edges = perc_graph.edges()

    # number of nodes N
    num_nodes = nx.number_of_nodes(perc_graph)

    # number of edges M
    num_edges = nx.number_of_edges(perc_graph)

    # initial iteration: no edges added yet (n == 0)
    ret = dict()

    ret['n'] = 0
    ret['N'] = num_nodes
    ret['M'] = num_edges
    ret['max_cluster_size'] = 1
    ret['moments'] = np.ones(5) * (num_nodes - 1)

    if spanning_cluster:
        ret['has_spanning_cluster'] = False

    if copy_result:
        yield copy.deepcopy(ret)
    else:
        yield ret

    # permute edges
    perm_edges = np.random.permutation(num_edges)

    # set up disjoint set (union-find) data structure
    ds = nx.utils.union_find.UnionFind()
    if spanning_cluster:
        ds_spanning = nx.utils.union_find.UnionFind()

        # merge all auxiliary nodes for each side
        side_roots = dict()
        for side in spanning_sides:
            nodes = [
                node for (node, node_side) in auxiliary_node_attributes.items()
                if node_side is side
            ]
            ds_spanning.union(*nodes)
            side_roots[side] = ds_spanning[nodes[0]]

        for (edge, edge_side) in auxiliary_edge_attributes.items():
            ds_spanning.union(side_roots[edge_side], *edge)

        side_roots = [
            ds_spanning[side_root] for side_root in side_roots.values()
        ]

    # get first node
    max_cluster_root = next(perc_graph.nodes_iter())

    # loop over all edges (n == 1..M)
    for n in range(num_edges):
        ret['n'] = n + 1

        # draw new edge from permutation
        edge_index = perm_edges[n]
        edge = perc_edges[edge_index]
        ret['edge'] = edge

        # find roots and weights
        roots = [
            ds[node] for node in edge
        ]
        weights = [
            ds.weights[root] for root in roots
        ]

        if roots[0] is not roots[1]:
            # not same cluster: union!
            ds.union(*roots)
            if spanning_cluster:
                ds_spanning.union(*roots)

                ret['has_spanning_cluster'] = (
                    ds_spanning[side_roots[0]] == ds_spanning[side_roots[1]]
                )

            # find new root and weight
            root = ds[edge[0]]
            weight = ds.weights[root]

            # moments and maximum cluster size

            # deduct the previous sub-maximum clusters from moments
            for i in [0, 1]:
                if roots[i] is max_cluster_root:
                    continue
                ret['moments'] -= weights[i] ** np.arange(5)

            if max_cluster_root in roots:
                # merged with maximum cluster
                max_cluster_root = root
                ret['max_cluster_size'] = weight
            else:
                # merged previously sub-maximum clusters
                if ret['max_cluster_size'] >= weight:
                    # previously largest cluster remains largest cluster
                    # add merged cluster to moments
                    ret['moments'] += weight ** np.arange(5)
                else:
                    # merged cluster overtook previously largest cluster
                    # add previously largest cluster to moments
                    max_cluster_root = root
                    ret['moments'] += ret['max_cluster_size'] ** np.arange(5)
                    ret['max_cluster_size'] = weight

        if copy_result:
            yield copy.deepcopy(ret)
        else:
            yield ret

Response: Generates a successive sample of the states of the given graph.