### 8 releases (breaking)

0.7.1 | Jan 23, 2024 |
---|---|

0.6.0 | Jan 22, 2024 |

0.5.3 | Mar 8, 2023 |

0.4.0 | May 29, 2020 |

0.1.1 | Apr 23, 2020 |

#**748** in Algorithms

**GPL-3.0**license

105KB

2.5K
SLoC

# nblast-rs

Implementation of NBLAST for neuron morphology comparisons, originally published here and implemented here.

This package is compatible with the reference implementation, but the API is subject to change.

## Benchmarking

Some benchmarks use optional features, and so benchmarkers should use

`cargo`` bench`` --`all-features

###
`lib.rs`

:

Implementation of the NBLAST algorithm for quantifying neurons' morphological similarity. Originally published in Costa et al. (2016) and implemented as part of the NeuroAnatomy Toolbox.

# Algorithm

Each neuron is passed in as a point cloud sample (the links between the points are not required).
A tangent vector is calculated for each point, based on its location and that of its nearest neighbors.
Additionally, an

value is calculated, which describes how colinear the neighbors are,
between 0 and 1.`alpha`

To query the similarity of neuron

to neuron `Q`

:`T`

- Take a point and its associated tangent in
`Q`- Find the nearest point in

, and its associated tangent`T` - Compute the distance between the two points
- Compute the absolute dot product of the two tangents
- Apply some empirically-derived function to the (distance, dot_product) tuple
- As published, this is the log probabity ratio of any pair belonging to closely related or unrelated neurons

- Find the nearest point in
- Repeat for all points, summing the results

The result is not easily comparable:
it is highly dependent on the size of the point cloud
and is not commutative, i.e.

.`f``(`Q`,` T`)` `!=` `f``(`T`,` Q`)`

To make queries between two pairs of neurons comparable,
the result can be normalized by the "self-hit" score of the query, i.e.

.`f``(`Q`,` Q`)`

To make the result commutative, the forward

and backward `f``(`Q`,` T`)`

scores can be combined in some way.
This library supports several means (arithmetic, harmonic, and geometric), the minimum, and the maximum.
The choice will depend on the application.
This can be applied after the scores are normalized.`f``(`T`,` Q`)`

The backbone of the neuron is the most easily sampled and most stereotyped part of its morphology, and therefore should be focused on for comparisons. However, a lot of cable is in dendrites, which can cause problems when reconstructed in high resolution. Queries can be weighted towards straighter, less branched regions by multiplying the absolute dot product for each point match by the geometric mean of the two alpha values.

More information on the algorithm can be found here.

# Usage

The QueryNeuron and TargetNeuron traits
define types which can be compared with NBLAST.
All

s are also `TargetNeuron`

s.
Both are Neurons.`QueryNeuron`

PointsTangentsAlphas and RstarNeuron implement these, respectively. Both can be created with pre-calculated tangents and alphas, or calculate them on instantiation.

The NblastArena contains a collection of

s
and a function to apply to pointwise DistDots to generate
a score for that point match, for convenient many-to-many comparisons.
A pre-calculated table of point match scores can be converted into a function with table_to_fn.`TargetNeuron`

`use` `nblast``::``{`NblastArena`,` ScoreCalc`,` Neuron`,` Symmetry`}``;`
`//` Create a lookup table for the point match scores
`let` smat `=` `ScoreCalc``::`table_from_bins`(`
`vec!``[``0.``0``,` `0.``1``,` `0.``25``,` `0.``5``,` `1.``0``,` `5.``0``,` `f64``::``INFINITY``]``,` `//` distance thresholds
`vec!``[``0.``0``,` `0.``2``,` `0.``4``,` `0.``6``,` `0.``8``,` `1.``0``]``,` `//` dot product thresholds
`vec!``[` `//` table values in dot-major order
`0.``0``,` `0.``1``,` `0.``2``,` `0.``3``,` `0.``4``,`
`1.``0``,` `1.``1``,` `1.``2``,` `1.``3``,` `1.``4``,`
`2.``0``,` `2.``1``,` `2.``2``,` `2.``3``,` `2.``4``,`
`3.``0``,` `3.``1``,` `3.``2``,` `3.``3``,` `3.``4``,`
`4.``0``,` `4.``1``,` `4.``2``,` `4.``3``,` `4.``4``,`
`5.``0``,` `5.``1``,` `5.``2``,` `5.``3``,` `5.``4``,`
`]``,`
`)``.``expect``(``"`could not build score matrix`"``)``;`
`//` See the ScoreMatrixBuilder for constructing a score matrix from test data.
`//` Create an arena to hold your neurons with this score function, and
`//` whether it should scale the dot products by the colinearity value.
`let` `mut` arena `=` `NblastArena``::`new`(`smat`,` `false``)``;`
`//` if the "parallel" feature is enabled, use e.g. `.with_threads(5)` to set 5 threads for multi-neuron queries
`let` `mut` rng `=` `fastrand``::``Rng``::`with_seed`(``1991``)``;`
`fn` `random_points``(``n``:` `usize`, `rng``:` `&``mut` `fastrand``::`Rng`)`` ``->` `Vec``<``[``f64``;` `3``]``>` `{`
`std``::``iter``::`repeat_with`(``|``|` `[`
`10.``0` `*` rng`.``f64``(``)``,`
`10.``0` `*` rng`.``f64``(``)``,`
`10.``0` `*` rng`.``f64``(``)``,`
`]``)``.``take``(`n`)``.``collect``(``)`
`}`
`//` Add some neurons built from points and a neighborhood size,
`//` returning their indices in the arena
`let` idx1 `=` arena`.``add_neuron``(`
`Neuron``::`new`(``random_points``(``6``,` `&``mut` rng`)``,` `5``)``.``expect``(``"`cannot construct neuron`"``)`
`)``;`
`let` idx2 `=` arena`.``add_neuron``(`
`Neuron``::`new`(``random_points``(``8``,` `&``mut` rng`)``,` `5``)``.``expect``(``"`cannot construct neuron`"``)`
`)``;`
`//` get a raw score (not normalized by self-hit, no symmetry)
`let` raw `=` arena`.``query_target``(`idx1`,` idx2`,` `false``,` `&``None``)``;`
`//` get all the scores, normalized, made symmetric, and with a centroid distance cut-off
`let` results `=` arena`.``all_v_all``(``true``,` `&``Some``(``Symmetry``::`ArithmeticMean`)``,` `Some``(``10.``0``)``)``;`

#### Dependencies

~7–31MB

~485K SLoC