<commit_before># Copyright (c) 2015, Ecole Polytechnique Federale de Lausanne, Blue Brain Project
# All rights reserved.
#
# This file is part of NeuroM <https://github.com/BlueBrain/NeuroM>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     1. Redistributions of source code must retain the above copyright
#        notice, this list of conditions and the following disclaimer.
#     2. Redistributions in binary form must reproduce the above copyright
#        notice, this list of conditions and the following disclaimer in the
#        documentation and/or other materials provided with the distribution.
#     3. Neither the name of the copyright holder nor the names of
#        its contributors may be used to endorse or promote products
#        derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

'''Neurite functions'''

import functools
from itertools import imap, chain
import numpy as np
from neurom.core.tree import (ipreorder,
                              ibifurcation_point,
                              iforking_point,
                              iupstream,
                              ileaf)
from neurom.core.types import tree_type_checker as is_type
from neurom.core.types import NeuriteType
from neurom.analysis import morphmath as mm
from . import Neurite
from ._sectionfunc import branch_order, section_radial_distance
from ._bifurcationfunc import (local_bifurcation_angle,
                               remote_bifurcation_angle,
                               bifurcation_partition)


def neurite_fun(fun):
    '''Wrapper to extract the neurite trees from the first parameter'''
    @functools.wraps(fun)
    def _neurites(obj, **kwargs):
        '''Extract neurites from obj and forward to wrapped function'''
        if hasattr(obj, 'neurites'):
            obj = obj.neurites
        elif isinstance(obj, Neurite):
            obj = (obj,)
        return fun(obj, **kwargs)

    return _neurites


@neurite_fun
def iter_sections(neurites, iterator_type=ipreorder, neurite_filter=None):
    '''Returns an iterator to the nodes in a iterable of neurite objects

    Parameters:
        neurites: iterable containing neurite objects
        iterator_type: type of the iteration (ipreorder, iupstream, ibifurcation_point)
        neurite_filter: optional top level filter on properties of neurite neurite objects.
    '''
    neurites = (neurites if neurite_filter is None
                else filter(neurite_filter, neurites))

    trees = (t.root_node if isinstance(t, Neurite) else t for t in neurites)

    return chain.from_iterable(imap(iterator_type, trees))


def n_segments(neurites, neurite_type=NeuriteType.all):
    '''Number of segments in a collection of neurites'''
    return sum(len(s.points) - 1
               for s in iter_sections(neurites, neurite_filter=is_type(neurite_type)))


@neurite_fun
def n_sections(neurites, neurite_type=NeuriteType.all):
    '''Number of sections in a collection of neurites'''
    return sum(1 for _ in iter_sections(neurites, neurite_filter=is_type(neurite_type)))


@neurite_fun
def n_neurites(neurites, neurite_type=NeuriteType.all):
    '''Number of neurites in a collection of neurites'''
    is_ntype = is_type(neurite_type)
    return sum(1 for n in neurites if is_ntype(n))


@neurite_fun
def n_bifurcation_points(neurites, neurite_type=NeuriteType.all):
    '''Number of bifurcation points in a collection of neurites'''
    return sum(1 for _ in iter_sections(neurites,
                                        iterator_type=ibifurcation_point,
                                        neurite_filter=is_type(neurite_type)))


@neurite_fun
def n_forking_points(neurites, neurite_type=NeuriteType.all):
    '''Number of forking points in a collection of neurites'''
    return sum(1 for _ in iter_sections(neurites,
                                        iterator_type=iforking_point,
                                        neurite_filter=is_type(neurite_type)))


@neurite_fun
def n_leaves(neurites, neurite_type=NeuriteType.all):
    '''Number of leaves in a collection of neurites'''
    return sum(1 for _ in iter_sections(neurites,
                                        iterator_type=ileaf,
                                        neurite_filter=is_type(neurite_type)))
<commit_msg>Refactor neurite feature functions.<commit_after># Copyright (c) 2015, Ecole Polytechnique Federale de Lausanne, Blue Brain Project
# All rights reserved.
#
# This file is part of NeuroM <https://github.com/BlueBrain/NeuroM>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     1. Redistributions of source code must retain the above copyright
#        notice, this list of conditions and the following disclaimer.
#     2. Redistributions in binary form must reproduce the above copyright
#        notice, this list of conditions and the following disclaimer in the
#        documentation and/or other materials provided with the distribution.
#     3. Neither the name of the copyright holder nor the names of
#        its contributors may be used to endorse or promote products
#        derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

'''Neurite functions'''

from functools import wraps, partial
from itertools import imap, chain
import numpy as np
from neurom.core.tree import (ipreorder,
                              ibifurcation_point,
                              iforking_point,
                              iupstream,
                              ileaf)
from neurom.core.types import tree_type_checker as is_type
from neurom.core.types import NeuriteType
from neurom.analysis import morphmath as mm
from . import Neurite
from ._sectionfunc import branch_order, section_radial_distance
from ._bifurcationfunc import (local_bifurcation_angle,
                               remote_bifurcation_angle,
                               bifurcation_partition)


def neurite_fun(fun):
    '''Wrapper to extract the neurite trees from the first parameter'''
    @wraps(fun)
    def _neurites(obj, **kwargs):
        '''Extract neurites from obj and forward to wrapped function'''
        if hasattr(obj, 'neurites'):
            obj = obj.neurites
        elif isinstance(obj, Neurite):
            obj = (obj,)
        return fun(obj, **kwargs)

    return _neurites


@neurite_fun
def iter_sections(neurites, iterator_type=ipreorder, neurite_filter=None):
    '''Returns an iterator to the nodes in a iterable of neurite objects

    Parameters:
        neurites: iterable containing neurite objects
        iterator_type: type of the iteration (ipreorder, iupstream, ibifurcation_point)
        neurite_filter: optional top level filter on properties of neurite neurite objects.
    '''
    neurites = (neurites if neurite_filter is None
                else filter(neurite_filter, neurites))

    trees = (t.root_node if isinstance(t, Neurite) else t for t in neurites)

    return chain.from_iterable(imap(iterator_type, trees))


def n_segments(neurites, neurite_type=NeuriteType.all):
    '''Number of segments in a collection of neurites'''
    return sum(len(s.points) - 1
               for s in iter_sections(neurites, neurite_filter=is_type(neurite_type)))


@neurite_fun
def n_neurites(neurites, neurite_type=NeuriteType.all):
    '''Number of neurites in a collection of neurites'''
    is_ntype = is_type(neurite_type)
    return sum(1 for n in neurites if is_ntype(n))


@neurite_fun
def n_sections(neurites, iterator_type=ipreorder, neurite_type=NeuriteType.all):
    '''Number of sections in a collection of neurites'''
    return sum(1 for _ in iter_sections(neurites,
                                        iterator_type=iterator_type,
                                        neurite_filter=is_type(neurite_type)))


n_bifurcation_points = partial(n_sections, iterator_type=ibifurcation_point)
n_forking_points = partial(n_sections, iterator_type=iforking_point)
n_leaves = partial(n_sections, iterator_type=ileaf)

{'fraction_non_alphanumeric': 0.0630139802631579, 'fraction_numerical': 0.0023643092105263158, 'mean_word_length': 3.1719554030874786, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6313798', 'n_tokens_mistral': 2707, 'n_tokens_neox': 2547, 'n_words': 982}