| Title: | B-cell Hybrid Immune Variant Engine |
|---|---|
| Description: | bHIVE implements an artificial immune network (AI-Net) for clustering and classification of high-dimensional data such as mass cytometry and single-cell profiles. A population of prototypes, called antibodies, evolves by clonal selection, somatic hypermutation and network suppression, and the learned prototypes summarize cell populations in the original marker units. The same fitted model clusters a dataset and labels new cells. bHIVE accepts SummarizedExperiment and SingleCellExperiment objects and integrates with bluster through bHIVEParam. A C++ backend computes affinities, mutations and suppression, and optional R6 modules add mechanisms such as germinal center selection, microenvironment-dependent mutation and isotype switching. The package also provides multilayer clustering, grid search and caret model wrappers. |
| Authors: | Nick Borcherding [aut, cre] (ORCID: <https://orcid.org/0000-0003-1427-6342>) |
| Maintainer: | Nick Borcherding <ncborch@gmail.com> |
| License: | MIT + file LICENSE |
| Version: | 0.99.8 |
| Built: | 2026-10-16 21:32:20 UTC |
| Source: | https://github.com/BiocStaging/bHIVE |
Two-signal activation gate implementing the immunological principle that immune cell activation requires both antigen-specific recognition (Signal 1) AND costimulatory context (Signal 2).
Prevents spurious activation on isolated outliers. An antibody is only allowed to clone if both signals exceed their thresholds. This is biologically-principled regularization.
Signal 2 options:
"density": Local data density around the antibody
"danger": User-provided danger signal vector
"entropy": Local label entropy (classification only)
An R6Class generator. ActivationGate$new()
returns an ActivationGate object.
signal2_typeType of costimulatory signal.
threshold1Minimum affinity for Signal 1 (antigen recognition).
threshold2Minimum costimulatory signal for Signal 2.
danger_signalsUser-provided danger signal vector (for "danger" type).
new()
Create a new ActivationGate.
ActivationGate$new( signal2_type = "density", threshold1 = 0.1, threshold2 = 0.3, danger_signals = NULL )
signal2_typeCharacter. "density", "danger", or "entropy".
threshold1Numeric. Minimum affinity threshold.
threshold2Numeric. Minimum Signal 2 threshold.
danger_signalsNumeric vector. Per-data-point danger scores.
evaluate()
Evaluate which antibody-data interactions pass the two-signal gate.
ActivationGate$evaluate(affinity_matrix, X, A, y = NULL, task = "clustering")
affinity_matrixNumeric matrix (n x m) of affinities.
XNumeric matrix of data (n x d).
ANumeric matrix of antibodies (m x d).
yTarget vector or NULL.
taskCharacter. Task type.
Logical matrix (n x m) where TRUE means the interaction is activated.
format()
Format a short summary, one element per line. Used by
print().
ActivationGate$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
ActivationGate$clone(deep = FALSE)
deepWhether to make a deep clone.
# Two-signal activation gate data(iris) X <- as.matrix(iris[, 1:4]) A <- X[sample(150, 10), ] rep <- ImmuneRepertoire$new(A) gate <- ActivationGate$new(signal2_type = "density", threshold2 = 0.3) aff <- rep$affinity_matrix(X, "gaussian") activated <- gate$evaluate(aff, X, A) sum(activated) # number of activated interactions# Two-signal activation gate data(iris) X <- as.matrix(iris[, 1:4]) A <- X[sample(150, 10), ] rep <- ImmuneRepertoire$new(A) gate <- ActivationGate$new(signal2_type = "density", threshold2 = 0.3) aff <- rep$affinity_matrix(X, "gaussian") activated <- gate$evaluate(aff, X, A) sum(activated) # number of activated interactions
R6 implementation of the Artificial Immune Network algorithm. This is the core bHIVE algorithm using C++ backends for performance-critical operations. Supports composable modules for somatic hypermutation, idiotypic network regulation, germinal center selection, and more.
An R6Class generator. AINet$new() returns
an AINet object. Call $fit() on it to train, then
$predict() to label new data.
bHIVE::ImmuneAlgorithm -> AINet
new()
Create a new AINet algorithm instance.
AINet$new(
nAntibodies = 20,
beta = 5,
epsilon = 0.01,
maxIter = 50,
k = 3,
affinityFunc = "gaussian",
distFunc = "euclidean",
affinityParams = list(alpha = 1, c = 1, p = 2, Sigma = NULL),
mutationDecay = 1,
mutationMin = 0.01,
maxClones = Inf,
stopTolerance = 0,
noImprovementLimit = Inf,
initMethod = "sample",
consolidate = TRUE,
consolidationSteps = 10L,
scale = c("none", "zscore", "robust", "arcsinh"),
scaleCofactor = 5,
targetK = NULL,
epsilonQuantile = NULL,
coverageBoost = FALSE,
coverageQuantile = 0.05,
minPerClass = 5,
shm = NULL,
init = NULL,
activation = NULL,
idiotypic = NULL,
germinalCenter = NULL,
microenvironment = NULL,
memory = NULL,
classSwitcher = NULL,
verbose = TRUE
)nAntibodiesInteger. Initial antibody population size.
betaNumeric. Clone multiplier.
epsilonNumeric. Suppression distance threshold.
maxIterInteger. Maximum iterations.
kInteger. Top-k antibodies to clone per data point.
affinityFuncCharacter. Affinity function name.
distFuncCharacter. Distance function name.
affinityParamsList. Parameters for affinity/distance functions.
mutationDecayNumeric. Per-iteration mutation rate decay.
mutationMinNumeric. Minimum mutation rate.
maxClonesNumeric. Maximum clones per antibody.
stopToleranceNumeric. Early stopping tolerance.
noImprovementLimitInteger. Early stopping patience.
initMethodCharacter. Initialization method.
consolidateLogical. For clustering, run Lloyd-style consolidation (an M-step) after affinity maturation so antibodies are pulled onto the data manifold and become true data-space prototypes. Has no effect on classification. Default TRUE.
consolidationStepsInteger. Maximum consolidation iterations.
scaleCharacter. Per-feature input scaling applied at fit()
and re-applied to new data at predict(). One of "none"
(default, no transform), "zscore" (center/SD), "robust"
(median / IQR, outlier-tolerant), or "arcsinh" (inverse
hyperbolic sine with cofactor scaleCofactor, the standard
mass-cytometry transform). Because epsilon, mutation scale, and
all distances live in feature units, scaling makes the same defaults
behave consistently across datasets of different magnitude.
scaleCofactorNumeric. Cofactor for scale = "arcsinh"
(asinh(x / cofactor)). Default 5 (CyTOF convention; use ~150 for
fluorescence flow).
targetKInteger or NULL. If set, force the clustering solution to
exactly targetK clusters. Affinity maturation still discovers
where prototypes belong, but the final consolidation seeds a K-means
(Lloyd) refinement at exactly targetK centroids: surviving
antibodies are agglomerated (if more than K) or split with k-means++ (if
fewer than K) before refinement. This decouples the reported cluster
count from the emergent suppression dynamics. NULL (default) keeps the
emergent, self-selected K. Ignored for classification.
epsilonQuantileNumeric in (0, 1) or NULL. If set, the suppression
threshold is recomputed each iteration as this quantile of the pairwise
distances among the current antibodies, making suppression scale-free
and adaptive instead of using the fixed epsilon. NULL (default)
uses the fixed epsilon.
coverageBoostLogical. Clustering only. After maturation, find
data points that no surviving antibody covers well (max affinity in the
bottom coverageQuantile tail) and seed fresh antibodies there
with k-means++. Counters the clonal-selection bias toward dense regions,
which otherwise leaves rare populations unrepresented. Pairs naturally
with targetK: the extra seeds give the forced-K refinement
candidate prototypes for sparse populations. Default FALSE.
coverageQuantileNumeric in (0, 1). Affinity-coverage tail that
defines "poorly covered" points for coverageBoost. Default 0.05.
minPerClassInteger. Classification only. Antibodies are seeded
per class: each class gets max(minPerClass, round(nAntibodies *
class share)) antibodies drawn from its own observations with
initMethod, and starts with that class label. Without this, a
rare class (for example a population of a few cells in a cytometry
sample) often receives no antibody at all and can never be
predicted. The total can slightly exceed nAntibodies. Set to 0
to sample all observations without regard to class. Ignored when an
init module is supplied. Default 5. The guarantee holds at
seeding only: suppression and idiotypic regulation remove antibodies
afterwards and can take every one a class had. fit() reports
any class that ends with no antibody or that recovers less than half
of its own training observations, so raise nAntibodies or
lower epsilon when that happens.
shmAn SHMEngine instance or NULL for default uniform mutation.
initA VDJLibrary instance or NULL for default initialization.
activationAn ActivationGate instance or NULL.
idiotypicAn IdiotypicNetwork instance or NULL.
germinalCenterA GerminalCenter instance or NULL.
microenvironmentA Microenvironment instance or NULL.
memoryA MemoryPool instance or NULL.
classSwitcherA ClassSwitcher instance or NULL.
verboseLogical. Report progress with message(), so it can
be silenced with suppressMessages().
fit()
Fit the AINet algorithm to data.
AINet$fit(X, y = NULL, task = NULL, ...)
XNumeric matrix or data frame (n x d).
yOptional factor target for classification.
taskCharacter: "clustering" or "classification". Inferred from y if NULL.
...Additional arguments (currently unused).
Invisible self, with result populated.
clone()
The objects of this class are cloneable with this method.
AINet$clone(deep = FALSE)
deepWhether to make a deep clone.
# Clustering with Iris data data(iris) X <- as.matrix(iris[, 1:4]) model <- AINet$new(nAntibodies = 15, maxIter = 10, verbose = FALSE) model$fit(X, task = "clustering") table(model$result$assignments) # Classification model2 <- AINet$new(nAntibodies = 20, maxIter = 10, verbose = FALSE) model2$fit(X, iris$Species, task = "classification") mean(model2$result$assignments == as.character(iris$Species)) # Predict on new data preds <- model2$predict(X[1:10, ])# Clustering with Iris data data(iris) X <- as.matrix(iris[, 1:4]) model <- AINet$new(nAntibodies = 15, maxIter = 10, verbose = FALSE) model$fit(X, task = "clustering") table(model$result$assignments) # Classification model2 <- AINet$new(nAntibodies = 20, maxIter = 10, verbose = FALSE) model2$fit(X, iris$Species, task = "classification") mean(model2$result$assignments == as.character(iris$Species)) # Predict on new data preds <- model2$predict(X[1:10, ])
Implements an artificial immune network algorithm for clustering and classification tasks. The algorithm evolves a population of "antibodies" via clonal selection and mutation, applies network suppression to maintain diversity, and assigns data points based on affinity or distance metrics.
bHIVE(X, ...) ## S4 method for signature 'ANY' bHIVE( X, y = NULL, task = NULL, nAntibodies = 20, beta = 5, epsilon = 0.01, maxIter = 50, affinityFunc = "gaussian", distFunc = "euclidean", affinityParams = list(alpha = 1, c = 1, p = 2, Sigma = NULL), mutationDecay = 1, mutationMin = 0.01, maxClones = Inf, stopTolerance = 0, noImprovementLimit = Inf, initMethod = c("sample", "random", "random_uniform", "kmeans++"), k = 3, scale = c("none", "zscore", "robust", "arcsinh"), targetK = NULL, epsilonQuantile = NULL, verbose = TRUE, ... ) ## S4 method for signature 'SummarizedExperiment' bHIVE(X, y = NULL, ..., assay.type = "logcounts", name = "bHIVE") ## S4 method for signature 'SingleCellExperiment' bHIVE( X, y = NULL, ..., assay.type = "logcounts", use.dimred = NULL, name = "bHIVE" )bHIVE(X, ...) ## S4 method for signature 'ANY' bHIVE( X, y = NULL, task = NULL, nAntibodies = 20, beta = 5, epsilon = 0.01, maxIter = 50, affinityFunc = "gaussian", distFunc = "euclidean", affinityParams = list(alpha = 1, c = 1, p = 2, Sigma = NULL), mutationDecay = 1, mutationMin = 0.01, maxClones = Inf, stopTolerance = 0, noImprovementLimit = Inf, initMethod = c("sample", "random", "random_uniform", "kmeans++"), k = 3, scale = c("none", "zscore", "robust", "arcsinh"), targetK = NULL, epsilonQuantile = NULL, verbose = TRUE, ... ) ## S4 method for signature 'SummarizedExperiment' bHIVE(X, y = NULL, ..., assay.type = "logcounts", name = "bHIVE") ## S4 method for signature 'SingleCellExperiment' bHIVE( X, y = NULL, ..., assay.type = "logcounts", use.dimred = NULL, name = "bHIVE" )
X |
A numeric matrix or data frame of input features, with rows as observations and columns as features. Or a SummarizedExperiment or SingleCellExperiment with features in rows and cells in columns. |
... |
Additional arguments forwarded to |
y |
Optional. A factor target vector for classification. If NULL,
clustering will be performed. For SummarizedExperiment input, |
task |
Character. Specifies the task to perform: |
nAntibodies |
Integer. The initial population size of antibodies. |
beta |
Numeric. Clone multiplier (controls how many clones are generated for top-matching antibodies). |
epsilon |
Numeric. Similarity threshold used in network suppression;
antibodies closer than |
maxIter |
Integer. Maximum number of iterations to run the AI-Net algorithm. |
affinityFunc |
Character. Specifies the affinity (similarity) function
to use for antibody-data matching. One of |
distFunc |
Character. Specifies the distance function for clustering
and suppression. One of |
affinityParams |
A list of optional parameters for the chosen affinity or distance function.
|
mutationDecay |
Numeric. Factor by which the mutation rate decays each
iteration (should be |
mutationMin |
Numeric. Minimum mutation rate, preventing the mutation scale from shrinking to zero. |
maxClones |
Numeric. Maximum number of clones per top-matching antibody;
defaults to |
stopTolerance |
Numeric. If the change in the number of antibodies
(repertoire size) is |
noImprovementLimit |
Integer. Stops the algorithm early if there is no
further improvement in antibody count (beyond |
initMethod |
Character. Method for initializing antibodies. Can be:
|
k |
Integer. Number of top-matching antibodies (by affinity) to consider cloning for each data point. |
scale |
Character. Per-feature input scaling: |
targetK |
Integer or NULL. If set, force the clustering result to
exactly |
epsilonQuantile |
Numeric in (0, 1) or NULL. If set, the suppression
threshold adapts each iteration to this quantile of pairwise antibody
distances instead of the fixed |
verbose |
Logical. If |
assay.type |
String or integer. The assay holding the features to
cluster, for SummarizedExperiment input. Ignored when |
name |
String. The |
use.dimred |
String or integer. The |
bHIVE() accepts a plain matrix or data frame (observations in rows)
or a SummarizedExperiment /
SingleCellExperiment (features in rows, cells in columns, the
Bioconductor convention). For the latter, the cells are clustered or
classified using an assay or, for a SingleCellExperiment, a
reducedDim() embedding, and the labels are stored in
colData(). To use bHIVE through bluster, see
bHIVEParam.
For matrix or data frame input, a list:
antibodies: Final prototype matrix (prototypes x features),
in the scaled space the model was trained in.
assignments: For clustering, integer cluster IDs, where
cluster i is row i of antibodies. For
classification, the predicted class labels.
antibody_classes: Classification only. The class label of
each antibody.
antibody_index: Classification only. The row of
antibodies that labeled each observation.
antibodies_unscaled: The prototypes back-transformed to
the original feature units.
task: The chosen task.
model: The fitted AINet object. Use
res$model$predict(newdata) to label new observations.
For SummarizedExperiment or SingleCellExperiment input, X with the
labels added as a factor column colData(X)[[name]] and the full
result list above in metadata(X)[[name]].
bHIVEParam for bluster integration,
AINet for the underlying R6 engine.
# Example 1: Clustering with the Iris dataset data(iris) X <- as.matrix(iris[, 1:4]) # Numeric features only res <- bHIVE(X = X, task = "clustering", nAntibodies = 30, beta = 5, epsilon = 0.01, maxIter = 20, k = 3, verbose = FALSE) table(res$assignments) # Example 2: Classification with Iris species y <- iris$Species res <- bHIVE(X = X, y = y, task = "classification", nAntibodies = 30, beta = 5, epsilon = 0.01, maxIter = 20, k = 3, verbose = FALSE) table(res$assignments, y) # Example 3: SingleCellExperiment input (features x cells) library(SingleCellExperiment) sce <- SingleCellExperiment(assays = list(logcounts = t(X)), colData = DataFrame(species = iris$Species)) sce <- bHIVE(sce, targetK = 3, maxIter = 10, verbose = FALSE) table(sce$bHIVE, sce$species) # Cluster on an embedding, or classify with a colData column as labels reducedDim(sce, "PCA") <- prcomp(X)$x[, 1:2] sce <- bHIVE(sce, use.dimred = "PCA", name = "bHIVE_pca", verbose = FALSE) sce <- bHIVE(sce, y = "species", name = "bHIVE_class", verbose = FALSE) mean(sce$bHIVE_class == sce$species)# Example 1: Clustering with the Iris dataset data(iris) X <- as.matrix(iris[, 1:4]) # Numeric features only res <- bHIVE(X = X, task = "clustering", nAntibodies = 30, beta = 5, epsilon = 0.01, maxIter = 20, k = 3, verbose = FALSE) table(res$assignments) # Example 2: Classification with Iris species y <- iris$Species res <- bHIVE(X = X, y = y, task = "classification", nAntibodies = 30, beta = 5, epsilon = 0.01, maxIter = 20, k = 3, verbose = FALSE) table(res$assignments, y) # Example 3: SingleCellExperiment input (features x cells) library(SingleCellExperiment) sce <- SingleCellExperiment(assays = list(logcounts = t(X)), colData = DataFrame(species = iris$Species)) sce <- bHIVE(sce, targetK = 3, maxIter = 10, verbose = FALSE) table(sce$bHIVE, sce$species) # Cluster on an embedding, or classify with a colData column as labels reducedDim(sce, "PCA") <- prcomp(X)$x[, 1:2] sce <- bHIVE(sce, use.dimred = "PCA", name = "bHIVE_pca", verbose = FALSE) sce <- bHIVE(sce, y = "species", name = "bHIVE_class", verbose = FALSE) mean(sce$bHIVE_class == sce$species)
A custom model definition that lets caret::train() tune, resample
and evaluate bHIVE classifiers.
bHIVEmodelbHIVEmodel
A list with the components caret expects of a custom model.
Pass bHIVEmodel as the method of caret::train().
Training fits bHIVE with the tuned nAntibodies,
beta and epsilon. Further arguments given to
caret::train() (for example maxIter, scale or
immunology modules) are passed on to bHIVE(). Progress output is
off unless verbose = TRUE is passed. Prediction labels each new
observation with the class of its best-matching antibody, using the fitted
AINet model, so new data gets the same scaling and kernel as
the training data.
caret requires column names on x.
A list defining a custom caret model, for use as
caret::train(method = bHIVEmodel).
label"Artificial Immune Network (bHIVE)".
library"bHIVE".
type"Classification".
parametersThe tunable parameters: nAntibodies
(initial antibody count), beta (clone multiplier) and
epsilon (suppression threshold).
gridfunction(x, y, len, search). A default tuning
grid, regular (search = "grid") or random.
fitfunction(x, y, wts, param, lev, last, classProbs,
...). Fits bHIVE() and returns its result.
predictfunction(modelFit, newdata, submodels).
Returns a factor of predicted classes.
probNULL. Class probabilities are not implemented,
so caret::train() warns and continues if classProbs = TRUE.
bHIVE, honeycombHIVEmodel,
train
bHIVEmodel$label bHIVEmodel$parameters if (requireNamespace("caret", quietly = TRUE)) { X <- as.matrix(iris[, 1:4]) y <- iris$Species set.seed(42) fit <- caret::train( x = X, y = y, method = bHIVEmodel, trControl = caret::trainControl(method = "cv", number = 3), tuneGrid = data.frame(nAntibodies = 40, beta = 5, epsilon = 0.05), maxIter = 10 ) fit table(Predicted = predict(fit, X), Actual = y) }bHIVEmodel$label bHIVEmodel$parameters if (requireNamespace("caret", quietly = TRUE)) { X <- as.matrix(iris[, 1:4]) y <- iris$Species set.seed(42) fit <- caret::train( x = X, y = y, method = bHIVEmodel, trControl = caret::trainControl(method = "cv", number = 3), tuneGrid = data.frame(nAntibodies = 40, beta = 5, epsilon = 0.05), maxIter = 10 ) fit table(Predicted = predict(fit, X), Actual = y) }
Run bHIVE clustering through clusterRows,
the bluster interface that bluster::clusterSweep() builds
on. This makes bHIVE a drop-in
alternative to the k-means, SOM and graph-based clustering that
bluster already wraps.
bHIVEParam( nAntibodies = NULL, beta = NULL, epsilon = NULL, maxIter = NULL, k = NULL, affinityFunc = NULL, distFunc = NULL, initMethod = NULL, scale = NULL, targetK = NULL, epsilonQuantile = NULL, affinityParams = list(), ... ) ## S4 method for signature 'bHIVEParam' .defaultScalarArguments(x) ## S4 method for signature 'bHIVEParam' show(object) ## S4 method for signature 'ANY,bHIVEParam' clusterRows(x, BLUSPARAM, full = FALSE)bHIVEParam( nAntibodies = NULL, beta = NULL, epsilon = NULL, maxIter = NULL, k = NULL, affinityFunc = NULL, distFunc = NULL, initMethod = NULL, scale = NULL, targetK = NULL, epsilonQuantile = NULL, affinityParams = list(), ... ) ## S4 method for signature 'bHIVEParam' .defaultScalarArguments(x) ## S4 method for signature 'bHIVEParam' show(object) ## S4 method for signature 'ANY,bHIVEParam' clusterRows(x, BLUSPARAM, full = FALSE)
nAntibodies, beta, epsilon, maxIter, k, affinityFunc, distFunc, initMethod, scale, targetK, epsilonQuantile
|
Scalar arguments passed to |
affinityParams |
Named list passed to |
... |
Further named arguments passed to |
x |
A numeric matrix-like object with observations in rows, or a
|
object |
A |
BLUSPARAM |
A |
full |
Logical. Return the full |
bHIVE learns a set of prototypes (antibodies) by clonal selection, mutation
and network suppression, then assigns each observation to its nearest
prototype. By default the number of clusters emerges from suppression. Set
targetK to force exactly that many clusters. For mass cytometry,
scale = "arcsinh" and affinityParams = list(alpha = "auto")
are good starting points. Progress output is off unless verbose =
TRUE is passed through ....
bHIVEParam() returns a bHIVEParam object, a subclass
of BlusterParam.
clusterRows() returns a factor of cluster labels, one per row of
x. With full = TRUE it returns a list with
clusters and objects, where objects$bHIVE is the
bHIVE() result, including the fitted AINet model
in objects$bHIVE$model for labeling new cells.
bHIVE, clusterRows,
clusterSweep.
library(bluster) X <- as.matrix(iris[, 1:4]) p <- bHIVEParam(targetK = 3, maxIter = 10) p set.seed(1) clusters <- clusterRows(X, p) table(clusters, iris$Species) # Full output keeps the fitted model for labeling new cells out <- clusterRows(X, p, full = TRUE) out$objects$bHIVE$model$predict(X[1:5, ]) # Sweep over parameters sweep <- clusterSweep(X, bHIVEParam(maxIter = 5), nAntibodies = c(10, 30)) sweep$parameters # Cluster a SingleCellExperiment embedding and store the labels library(SingleCellExperiment) sce <- SingleCellExperiment(assays = list(logcounts = t(X))) reducedDim(sce, "PCA") <- prcomp(X)$x[, 1:3] colLabels(sce) <- clusterRows(reducedDim(sce, "PCA"), p) table(colLabels(sce), iris$Species)library(bluster) X <- as.matrix(iris[, 1:4]) p <- bHIVEParam(targetK = 3, maxIter = 10) p set.seed(1) clusters <- clusterRows(X, p) table(clusters, iris$Species) # Full output keeps the fitted model for labeling new cells out <- clusterRows(X, p, full = TRUE) out$objects$bHIVE$model$predict(X[1:5, ]) # Sweep over parameters sweep <- clusterSweep(X, bHIVEParam(maxIter = 5), nAntibodies = c(10, 30)) sweep$parameters # Cluster a SingleCellExperiment embedding and store the labels library(SingleCellExperiment) sce <- SingleCellExperiment(assays = list(logcounts = t(X))) reducedDim(sce, "PCA") <- prcomp(X)$x[, 1:3] colLabels(sce) <- clusterRows(reducedDim(sce, "PCA"), p) table(colLabels(sce), iris$Species)
Implements antibody isotype/class switching, allowing antibodies to change their matching breadth. Inspired by real B cell class switching from IgM (broad, pentameric) to IgG (specific, monomeric) to IgA (mucosal).
In bHIVE, class switching modifies the effective affinity kernel width:
IgM: Broad matching (large kernel width) – good for initial
exploration and capturing general patterns
IgG: Specific matching (small kernel width) – good for
fine-grained discrimination after patterns are identified
IgA: Boundary patrol (medium kernel width) – good for
maintaining coverage at decision boundaries
An R6Class generator. ClassSwitcher$new()
returns a ClassSwitcher object.
alpha_IgMKernel width for IgM mode (broad).
alpha_IgGKernel width for IgG mode (specific).
alpha_IgAKernel width for IgA mode (boundary).
new()
Create a new ClassSwitcher.
ClassSwitcher$new(alpha_IgM = 0.1, alpha_IgG = 5, alpha_IgA = 1)
alpha_IgMNumeric. Kernel width for broad matching.
alpha_IgGNumeric. Kernel width for specific matching.
alpha_IgANumeric. Kernel width for boundary matching.
switch_isotypes()
Determine appropriate isotype for each antibody based on its microenvironment zone.
ClassSwitcher$switch_isotypes(repertoire, zones)
repertoireAn ImmuneRepertoire.
zonesCharacter vector from Microenvironment assessment.
Named numeric vector of alpha values per antibody.
get_alpha()
Get alpha value for a given isotype.
ClassSwitcher$get_alpha(isotype)
isotypeCharacter. "IgM", "IgG", or "IgA".
Numeric.
format()
Format a short summary, one element per line. Used by
print().
ClassSwitcher$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
ClassSwitcher$clone(deep = FALSE)
deepWhether to make a deep clone.
# Switch antibody isotypes based on microenvironment zones A <- matrix(rnorm(50), nrow = 10, ncol = 5) rep <- ImmuneRepertoire$new(A) cs <- ClassSwitcher$new(alpha_IgM = 0.1, alpha_IgG = 5.0) zones <- sample(c("stable", "explore", "boundary"), 10, replace = TRUE) alphas <- cs$switch_isotypes(rep, zones) table(rep$metadata$isotype) # IgM, IgG, IgA distribution# Switch antibody isotypes based on microenvironment zones A <- matrix(rnorm(50), nrow = 10, ncol = 5) rep <- ImmuneRepertoire$new(A) cs <- ClassSwitcher$new(alpha_IgM = 0.1, alpha_IgG = 5.0) zones <- sample(c("stable", "explore", "boundary"), 10, replace = TRUE) alphas <- cs$switch_isotypes(rep, zones) table(rep$metadata$isotype) # IgM, IgG, IgA distribution
Identifies "public antibodies" shared across independent repertoires, implementing the concept of convergent selection from TCR/BCR immunology as a biologically-motivated ensemble method.
In real immunity, certain immune receptor sequences appear across multiple individuals (public clones), suggesting they are driven by common selection pressures. Similarly, antibodies that appear across multiple independent bHIVE runs represent the most robust patterns in the data.
An R6Class generator.
ConvergentSelector$new() returns a ConvergentSelector object.
toleranceDistance tolerance for matching antibodies across repertoires.
min_appearancesMinimum number of repertoires an antibody must appear in to be considered "public".
public_antibodiesThe identified public antibodies.
new()
Create a new ConvergentSelector.
ConvergentSelector$new(tolerance = 0.5, min_appearances = 2)
toleranceNumeric. Maximum distance for two antibodies to be considered the same across repertoires.
min_appearancesInteger. Minimum repertoires for an antibody to be public.
find_public()
Find public antibodies shared across multiple repertoires.
ConvergentSelector$find_public(repertoires, distFunc = "euclidean")
repertoiresList of ImmuneRepertoire objects or list of antibody matrices.
distFuncCharacter. Distance function for matching.
Numeric matrix of public (consensus) antibodies.
from_results()
Run convergent selection from multiple bHIVE results.
ConvergentSelector$from_results(results, distFunc = "euclidean")
resultsList of bHIVE result objects (each with $antibodies).
distFuncCharacter. Distance function.
Numeric matrix of consensus antibodies.
format()
Format a short summary, one element per line. Used by
print().
ConvergentSelector$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
ConvergentSelector$clone(deep = FALSE)
deepWhether to make a deep clone.
# Find public antibodies across multiple runs data(iris) X <- as.matrix(iris[, 1:4]) results <- lapply(1:3, function(i) { m <- AINet$new(nAntibodies = 15, maxIter = 5, verbose = FALSE) m$fit(X, task = "clustering") m$result }) conv <- ConvergentSelector$new(tolerance = 1.0, min_appearances = 2) public <- conv$from_results(results) nrow(public) # consensus antibodies# Find public antibodies across multiple runs data(iris) X <- as.matrix(iris[, 1:4]) results <- lapply(1:3, function(i) { m <- AINet$new(nAntibodies = 15, maxIter = 5, verbose = FALSE) m$fit(X, task = "clustering") m$result }) conv <- ConvergentSelector$new(tolerance = 1.0, min_appearances = 2) public <- conv$from_results(results) nrow(public) # consensus antibodies
Models T follicular helper (Tfh) cell selection pressure on B cells within a germinal center reaction. Implements resource competition where antibodies compete for Tfh help, and only helped antibodies survive.
The germinal center is where B cells undergo affinity maturation through iterative cycles of mutation and selection. Tfh cells act as quality-control selectors:
Each Tfh evaluates B cell (antibody) quality using a task-aware metric
B cells compete for Tfh help (resource competition)
Only helped B cells survive to the next round
Selection pressure controls the stringency of the process
An R6Class generator. GerminalCenter$new()
returns a GerminalCenter object.
nTfhNumber of Tfh selectors (determines how many antibodies survive).
selectionPressureNumeric [0,1]. 0 = no selection (all survive), 1 = only the very best survive.
roundsNumber of selection rounds per call.
last_survivorsInteger vector of survivor indices (relative
to the input repertoire) from the most recent call to select().
new()
Create a new GerminalCenter.
GerminalCenter$new(nTfh = 10, selectionPressure = 0.5, rounds = 1)
nTfhInteger. Number of Tfh helper cells. Each helps one B cell.
selectionPressureNumeric [0,1]. Stringency of selection.
roundsInteger. Number of competition rounds.
select()
Run germinal center selection on a repertoire.
GerminalCenter$select( repertoire, X, y = NULL, task = "clustering", affinityFunc = "gaussian", affinityParams = list(alpha = 1, c = 1, p = 2) )
repertoireAn ImmuneRepertoire object.
XNumeric matrix of training data.
yFactor target vector or NULL for clustering.
taskCharacter: "clustering" or "classification".
affinityFuncCharacter. Affinity function for evaluation.
affinityParamsList. Parameters for affinity function.
Integer vector of survivor indices relative to the input
repertoire (composed across all selection rounds). Also stored on
self$last_survivors for inspection. Repertoire is modified
in place.
format()
Format a short summary, one element per line. Used by
print().
GerminalCenter$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
GerminalCenter$clone(deep = FALSE)
deepWhether to make a deep clone.
# Germinal center selection on Iris data(iris) X <- as.matrix(iris[, 1:4]) gc <- GerminalCenter$new(nTfh = 5, selectionPressure = 0.5) rep <- ImmuneRepertoire$new(X[sample(150, 20), ]) gc$select(rep, X, iris$Species, "classification") rep$size() # fewer antibodies after selection# Germinal center selection on Iris data(iris) X <- as.matrix(iris[, 1:4]) gc <- GerminalCenter$new(nTfh = 5, selectionPressure = 0.5) rep <- ImmuneRepertoire$new(X[sample(150, 20), ]) gc$select(rep, X, iris$Species, "classification") rep$size() # fewer antibodies after selection
The honeycombHIVE function implements a multilayer artificial immune
system that iteratively refines a set of prototypes - referred to as
antibodies - to model the structure of the input data. In each layer, the
function first uses the bHIVE algorithm to generate or update
antibodies based on the current data representation and task (clustering or
classification). Optionally, it applies gradient-based
fine-tuning (via refineB) to these antibodies, allowing for
advanced refinement through various optimizers (e.g., SGD, Adam, RMSProp) and
customizable loss functions. The final output is a hierarchical set of layers
that encapsulate both the refined prototypes and the corresponding cluster
assignments or predictions for the original observations, making
honeycombHIVE a versatile tool for adaptive learning and pattern
recognition.
honeycombHIVE( X, y = NULL, task = c("clustering", "classification"), layers = 3, nAntibodies = 20, minAntibodies = 5, epsilon = 0.05, beta = 5, maxIter = 10, collapseMethod = c("centroid", "medoid", "median", "mode"), minClusterSize = NULL, smallClusterAction = c("merge", "keep", "drop"), distance = "euclidean", verbose = TRUE, refine = FALSE, refineLoss = "categorical_crossentropy", refineSteps = 5, refineLR = 0.01, refinePushAway = TRUE, refineOptimizer = "sgd", refineMomentumCoef = 0.9, refineBeta1 = 0.9, refineBeta2 = 0.999, refineRmspropDecay = 0.9, refineEpsilon = 1e-08, ... )honeycombHIVE( X, y = NULL, task = c("clustering", "classification"), layers = 3, nAntibodies = 20, minAntibodies = 5, epsilon = 0.05, beta = 5, maxIter = 10, collapseMethod = c("centroid", "medoid", "median", "mode"), minClusterSize = NULL, smallClusterAction = c("merge", "keep", "drop"), distance = "euclidean", verbose = TRUE, refine = FALSE, refineLoss = "categorical_crossentropy", refineSteps = 5, refineLR = 0.01, refinePushAway = TRUE, refineOptimizer = "sgd", refineMomentumCoef = 0.9, refineBeta1 = 0.9, refineBeta2 = 0.999, refineRmspropDecay = 0.9, refineEpsilon = 1e-08, ... )
X |
A numeric matrix or data frame of input features (rows = observations, columns = features). |
y |
Optional target factor vector for classification. |
task |
Character, one of "clustering" or "classification". |
layers |
Integer, how many layers (AIS iterations) to run. |
nAntibodies |
Integer, how many antibodies (prototypes) to generate initially in each layer. |
minAntibodies |
Integer, minimal number of antibodies to keep in each layer. |
epsilon |
Numeric, threshold param for |
beta |
Numeric, selection pressure param for |
maxIter |
Integer, maximum iterations for |
collapseMethod |
One of "centroid","medoid","median","mode". |
minClusterSize |
Minimum cluster size. Clusters with fewer members are
handled per |
smallClusterAction |
One of |
distance |
Distance metric for medoid calculation, e.g. "euclidean". |
verbose |
Logical, if TRUE reports progress at each layer with
|
refine |
Logical, if TRUE apply gradient-based refinement via
|
refineLoss |
Character specifying the loss for |
refineSteps |
Integer, number of gradient steps in |
refineLR |
Numeric, learning rate for gradient updates. |
refinePushAway |
Logical, if TRUE and classification, push prototypes away from differently labeled points. |
refineOptimizer |
Character, one of |
refineMomentumCoef |
Numeric, momentum coefficient (if using momentum). |
refineBeta1 |
Numeric, first moment decay rate (if using Adam). |
refineBeta2 |
Numeric, second moment decay rate (if using Adam). |
refineRmspropDecay |
Numeric, decay rate for the moving average of squared gradients (if using RMSProp). |
refineEpsilon |
Numeric, a small constant for numerical stability (used in adaptive optimizers). |
... |
Additional arguments passed to |
A list of length layers. Each element (layer) is the
bHIVE result for that layer plus:
antibodies: The antibodies learned in that layer.
assignments: For each row of the layer's input (the
original rows for layer 1, the previous layer's prototypes after that),
the cluster ID or, for classification, the class label.
prototypes: The collapsed prototypes that feed the next
layer, one row per cluster. Row k summarizes the original
observations with membership == k.
membership: For each original row in X,
the row of prototypes it belongs to (NA if its cluster
was dropped).
predictions: For classification, the predicted label for
each original row: the majority label of its cluster.
model: Final layer only. The fitted AINet
model, for labeling new observations with $predict().
task: The specified task.
For classification, each layer collapses observations by the antibody that labeled them, so a layer keeps several prototypes per class.
# Clustering data(iris) X_iris <- iris[, 1:4] resC <- honeycombHIVE( X = X_iris, task = "clustering", layers = 3, nAntibodies = 15, beta = 5, maxIter = 10 )# Clustering data(iris) X_iris <- iris[, 1:4] resC <- honeycombHIVE( X = X_iris, task = "clustering", layers = 3, nAntibodies = 15, beta = 5, maxIter = 10 )
A custom model definition that lets caret::train() tune, resample
and evaluate honeycombHIVE classifiers with gradient-based
refinement.
honeycombHIVEmodelhoneycombHIVEmodel
A list with the components caret expects of a custom model.
Training runs honeycombHIVE(refine = TRUE) with the tuned
parameters. Further arguments given to caret::train() are passed on
to honeycombHIVE(). Progress output is off unless
verbose = TRUE is passed. Prediction uses the fitted
AINet model of the final layer. caret requires column names
on x. Class probabilities are not implemented (prob = NULL).
A list defining a custom caret model, for use as
caret::train(method = honeycombHIVEmodel).
nAntibodies: Number of initial antibodies per layer.
beta: Clone multiplier controlling the number of clones per
antibody.
epsilon: Threshold for network suppression to remove
redundant antibodies.
layers: Number of hierarchical layers.
refineOptimizer: Optimizer for gradient-based refinement
("sgd", "momentum", "adagrad", "adam" or "rmsprop").
refineSteps: Number of gradient update steps in refinement.
refineLR: Learning rate for refinement.
honeycombHIVE, bHIVEmodel,
train
if (requireNamespace("caret", quietly = TRUE)) { X <- as.matrix(iris[, 1:4]) y <- iris$Species set.seed(42) fit <- caret::train( x = X, y = y, method = honeycombHIVEmodel, trControl = caret::trainControl(method = "cv", number = 3), tuneGrid = data.frame(nAntibodies = 30, beta = 5, epsilon = 0.05, layers = 2, refineOptimizer = "adam", refineSteps = 3, refineLR = 0.01), maxIter = 10 ) fit table(Predicted = predict(fit, X), Actual = y) }if (requireNamespace("caret", quietly = TRUE)) { X <- as.matrix(iris[, 1:4]) y <- iris$Species set.seed(42) fit <- caret::train( x = X, y = y, method = honeycombHIVEmodel, trControl = caret::trainControl(method = "cv", number = 3), tuneGrid = data.frame(nAntibodies = 30, beta = 5, epsilon = 0.05, layers = 2, refineOptimizer = "adam", refineSteps = 3, refineLR = 0.01), maxIter = 10 ) fit table(Predicted = predict(fit, X), Actual = y) }
Implements Jerne's idiotypic network theory for antibody repertoire regulation. Replaces crude epsilon-threshold suppression with principled network dynamics based on Varela & Coutinho's (1991) second- generation immune network model.
The idiotypic network models antibody-antibody interactions where each antibody's variable region can be recognized by other antibodies. This creates a regulatory network with emergent properties:
- A bell-shaped (double-threshold) activation function: too little stimulation leads to cell death, moderate stimulation to activation, and excessive stimulation to suppression. - Population dynamics with source, decay, activation, and suppression terms. - Self-organized repertoire structure with memory and tolerance properties.
This is the single most novel contribution of the overhauled bHIVE package. No existing AIS implementation uses idiotypic network dynamics for repertoire regulation.
An R6Class generator.
IdiotypicNetwork$new() returns an IdiotypicNetwork object.
The activation rule is applied to each antibody pair and the responses are
summed: every neighbor whose affinity falls outside
[theta_low, theta_high] counts as one unit of suppression. In a
small, tight repertoire this culls crowded and isolated antibodies as
intended (see the example). In a large or spread-out repertoire most pairs
are far apart, their affinity is near zero, and every antibody is
suppressed. regulate() then warns and leaves the repertoire
unchanged, and AINet keeps the top 10% by population and
reports it with a message. Treat the module as experimental and check that
antibodies survive on your data. A field-based form, in which the
activation acts on the total stimulation each antibody receives, is
planned.
theta_lowLower activation threshold. Below this, cells die.
theta_highUpper activation threshold. Above this, cells are suppressed.
source_rateRate of new cell generation (basal production).
decay_rateNatural cell death rate.
dtTime step for Euler integration.
timeStepsNumber of simulation time steps.
survival_thresholdMinimum population level to survive.
last_dynamicsResult from the last regulation step.
new()
Create a new IdiotypicNetwork regulator.
IdiotypicNetwork$new( theta_low = 0.01, theta_high = 0.5, source_rate = 0.5, decay_rate = 0.1, dt = 0.1, timeSteps = 20, survival_threshold = 0.5 )
theta_lowLower activation threshold.
theta_highUpper activation threshold.
source_rateBasal cell production rate.
decay_rateNatural decay rate.
dtEuler integration time step.
timeStepsNumber of dynamics simulation steps.
survival_thresholdMinimum population to survive.
regulate()
Run idiotypic network dynamics on an antibody repertoire.
IdiotypicNetwork$regulate( repertoire, affinityFunc = "gaussian", affinityParams = list(alpha = 1, c = 1, p = 2) )
repertoireAn ImmuneRepertoire object.
affinityFuncCharacter. Affinity function for Ab-Ab interactions.
affinityParamsList. Parameters for the affinity function.
Invisible self. The repertoire is modified in place (dead
antibodies removed). Access $last_dynamics for full results.
get_network()
Get the Ab-Ab affinity matrix from the last regulation.
IdiotypicNetwork$get_network()
Numeric matrix (m x m) or NULL if not yet run.
get_population()
Get population levels from the last regulation.
IdiotypicNetwork$get_population()
Numeric vector or NULL if not yet run.
format()
Format a short summary, one element per line. Used by
print().
IdiotypicNetwork$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
IdiotypicNetwork$clone(deep = FALSE)
deepWhether to make a deep clone.
# Four antibodies with pairwise affinity 0.25 (inside the default # activation window) stimulate each other and survive. A fifth, far from # the rest, is under-stimulated and dies. a <- sqrt(log(4) / 2) A <- rbind(cbind(diag(4) * a, 0), c(0, 0, 0, 0, 10)) rep <- ImmuneRepertoire$new(A) idi <- IdiotypicNetwork$new(theta_low = 0.01, theta_high = 0.5) idi$regulate(rep, "gaussian", list(alpha = 1)) print(idi) rep$size()# Four antibodies with pairwise affinity 0.25 (inside the default # activation window) stimulate each other and survive. A fifth, far from # the rest, is under-stimulated and dies. a <- sqrt(log(4) / 2) A <- rbind(cbind(diag(4) * a, 0), c(0, 0, 0, 0, 10)) rep <- ImmuneRepertoire$new(A) idi <- IdiotypicNetwork$new(theta_low = 0.01, theta_high = 0.5) idi$regulate(rep, "gaussian", list(alpha = 1)) print(idi) rep$size()
Abstract R6 base class for all immune-inspired algorithms.
Subclasses must implement the fit method.
An R6Class generator. ImmuneAlgorithm$new()
returns an ImmuneAlgorithm object. It is an abstract base class: use
AINet for a fitted model.
repertoireAn ImmuneRepertoire object.
configNamed list of algorithm hyperparameters.
modulesNamed list of injected module instances (SHMEngine, IdiotypicNetwork, GerminalCenter, etc.).
historyList of per-iteration metrics.
resultThe result from the last call to fit().
new()
Create a new ImmuneAlgorithm.
ImmuneAlgorithm$new(config = list(), modules = list())
configNamed list of hyperparameters.
modulesNamed list of module instances.
fit()
Fit the algorithm to data. Must be overridden by subclasses.
ImmuneAlgorithm$fit(X, y = NULL, task = NULL, ...)
XNumeric matrix (n x d).
yOptional factor target for classification.
taskCharacter: "clustering" or "classification".
...Additional arguments.
The algorithm object (invisibly), with result populated.
predict()
Predict on new data using the trained repertoire.
ImmuneAlgorithm$predict(newdata)
newdataNumeric matrix (n_new x d).
Predictions (class labels, numeric values, or cluster IDs).
format()
Format a short summary, one element per line. Used by
print().
ImmuneAlgorithm$format(...)
...Not used.
A character vector.
summary()
Get a summary of the fitting history.
ImmuneAlgorithm$summary()
Data frame of per-iteration metrics.
clone()
The objects of this class are cloneable with this method.
ImmuneAlgorithm$clone(deep = FALSE)
deepWhether to make a deep clone.
# ImmuneAlgorithm is abstract; use AINet for concrete instances algo <- ImmuneAlgorithm$new() print(algo)# ImmuneAlgorithm is abstract; use AINet for concrete instances algo <- ImmuneAlgorithm$new() print(algo)
R6 class representing a collection of antibodies (immune cells) with associated metadata. Core data structure for bHIVE algorithms.
An ImmuneRepertoire holds a matrix of antibody vectors (each row is one antibody in feature space) plus per-antibody metadata (isotype, state, age, lineage). All heavy computation is dispatched to C++ via RcppArmadillo.
An R6Class generator.
ImmuneRepertoire$new() returns an ImmuneRepertoire object.
cellsNumeric matrix (nAntibodies x nFeatures).
metadataData frame with per-antibody attributes.
new()
Create a new ImmuneRepertoire.
ImmuneRepertoire$new(cells, metadata = NULL)
cellsNumeric matrix (nAntibodies x nFeatures).
metadataOptional data frame with columns: isotype, state, age, lineage.
affinity_matrix()
Compute affinity matrix between data X and antibodies.
ImmuneRepertoire$affinity_matrix( X, method = "gaussian", params = list(alpha = 1, c = 1, p = 2) )
XNumeric matrix (n x d) of data points.
methodAffinity function: "gaussian", "laplace", "polynomial", "cosine", "hamming".
paramsList with alpha, c, p parameters.
Numeric matrix (n x m) of affinity values.
distance_matrix()
Compute distance matrix between data X and antibodies.
ImmuneRepertoire$distance_matrix( X, method = "euclidean", params = list(p = 2, Sigma = NULL) )
XNumeric matrix (n x d).
methodDistance function: "euclidean", "manhattan", "minkowski", "cosine", "mahalanobis", "hamming".
paramsList with p, Sigma parameters.
Numeric matrix (n x m) of distances.
suppress()
Network suppression: remove redundant antibodies.
ImmuneRepertoire$suppress( epsilon, method = "euclidean", params = list(p = 2, Sigma = NULL) )
epsilonDistance threshold for suppression.
methodDistance function for suppression.
paramsList with p, Sigma parameters.
Invisible self (modified in place).
size()
Get number of antibodies.
ImmuneRepertoire$size()
Integer.
n_features()
Get number of features.
ImmuneRepertoire$n_features()
Integer.
subset()
Subset the repertoire.
ImmuneRepertoire$subset(idx)
idxInteger vector of row indices to keep.
Invisible self (modified in place).
add()
Add antibodies to the repertoire.
ImmuneRepertoire$add(new_cells, new_metadata = NULL)
new_cellsNumeric matrix (k x d) of new antibodies.
new_metadataOptional data frame of metadata for new antibodies.
Invisible self (modified in place).
age_all()
Increment age of all antibodies.
ImmuneRepertoire$age_all()
Invisible self (modified in place).
as_matrix()
Convert to plain matrix.
ImmuneRepertoire$as_matrix()
Numeric matrix (nAntibodies x nFeatures).
format()
Format a short summary, one element per line. Used by
print().
ImmuneRepertoire$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
ImmuneRepertoire$clone(deep = FALSE)
deepWhether to make a deep clone.
# Create a repertoire from random antibodies A <- matrix(rnorm(50), nrow = 10, ncol = 5) rep <- ImmuneRepertoire$new(A) print(rep) # Compute affinity to data X <- matrix(rnorm(100), nrow = 20, ncol = 5) aff <- rep$affinity_matrix(X, "gaussian", list(alpha = 1)) dim(aff) # 20 x 10 # Network suppression rep$suppress(epsilon = 1.5, method = "euclidean") rep$size() # fewer antibodies after suppression# Create a repertoire from random antibodies A <- matrix(rnorm(50), nrow = 10, ncol = 5) rep <- ImmuneRepertoire$new(A) print(rep) # Compute affinity to data X <- matrix(rnorm(100), nrow = 20, ncol = 5) aff <- rep$affinity_matrix(X, "gaussian", list(alpha = 1)) dim(aff) # 20 x 10 # Network suppression rep$suppress(epsilon = 1.5, method = "euclidean") rep$size() # fewer antibodies after suppression
Manages long-lived memory cells that can be recalled when distribution shifts are detected. Implements the immunological distinction between short-lived effector cells and long-lived memory cells.
An R6Class generator. MemoryPool$new()
returns a MemoryPool object.
memory_cellsNumeric matrix of archived memory antibodies.
memory_metadataData frame of metadata for memory cells.
archive_thresholdAffinity threshold for archiving (only high-quality antibodies become memory).
max_memoryMaximum number of memory cells to store.
recall_thresholdThreshold for triggering memory recall.
new()
Create a new MemoryPool.
MemoryPool$new( archive_threshold = 0.5, max_memory = 100, recall_threshold = 0.3 )
archive_thresholdNumeric. Minimum average affinity to archive.
max_memoryInteger. Maximum memory cells.
recall_thresholdNumeric. Minimum affinity to recall a memory.
archive()
Archive high-performing antibodies as memory cells.
MemoryPool$archive( repertoire, X, affinityFunc = "gaussian", affinityParams = list(alpha = 1, c = 1, p = 2) )
repertoireAn ImmuneRepertoire.
XTraining data matrix.
affinityFuncCharacter. Affinity function.
affinityParamsList. Affinity parameters.
Integer. Number of new memory cells archived.
recall()
Recall memory cells relevant to current data.
MemoryPool$recall( X, affinityFunc = "gaussian", affinityParams = list(alpha = 1, c = 1, p = 2) )
XData matrix to match against memory.
affinityFuncCharacter. Affinity function.
affinityParamsList. Affinity parameters.
Numeric matrix of recalled memory cells (may be empty).
size()
Get current memory pool size.
MemoryPool$size()
Integer.
format()
Format a short summary, one element per line. Used by
print().
MemoryPool$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
MemoryPool$clone(deep = FALSE)
deepWhether to make a deep clone.
# Archive and recall memory cells data(iris) X <- as.matrix(iris[, 1:4]) A <- X[sample(150, 10), ] mp <- MemoryPool$new(archive_threshold = 0.01) rep <- ImmuneRepertoire$new(A) mp$archive(rep, X) mp$size() # number of archived memories recalled <- mp$recall(X[1:5, ]) nrow(recalled) # memories relevant to query# Archive and recall memory cells data(iris) X <- as.matrix(iris[, 1:4]) A <- X[sample(150, 10), ] mp <- MemoryPool$new(archive_threshold = 0.01) rep <- ImmuneRepertoire$new(A) mp$archive(rep, X) mp$size() # number of archived memories recalled <- mp$recall(X[1:5, ]) nrow(recalled) # memories relevant to query
Models local microenvironment cues that influence antibody behavior based on the density and structure of nearby data points.
In real immunity, B cell fate is strongly influenced by local signals: chemokines, cytokines, and interactions with stromal cells in specific tissue microenvironments. This module translates that concept into density-dependent adaptation:
High density zones: Promote memory formation (stabilize antibodies, reduce mutation rate)
Low density zones: Promote exploration (increase mutation rate for broader search)
Boundary zones: Trigger class switching (change matching breadth between IgM-like broad and IgG-like specific modes)
Chemokine-like gradients: Bias mutation direction toward higher-density regions
An R6Class generator.
Microenvironment$new() returns a Microenvironment object.
density_bandwidthBandwidth for kernel density estimation.
high_density_thresholdDensity percentile above which antibodies stabilize.
low_density_thresholdDensity percentile below which antibodies explore.
stabilization_factorMutation rate multiplier for high-density zones.
exploration_factorMutation rate multiplier for low-density zones.
last_densitiesPer-antibody local density from last assessment.
last_zonesPer-antibody zone classification from last assessment.
new()
Create a new Microenvironment module.
Microenvironment$new( density_bandwidth = NULL, high_density_threshold = 0.75, low_density_threshold = 0.25, stabilization_factor = 0.3, exploration_factor = 2 )
density_bandwidthNumeric. KDE bandwidth (NULL for auto).
high_density_thresholdNumeric [0,1]. Percentile threshold for stabilization.
low_density_thresholdNumeric [0,1]. Percentile threshold for exploration.
stabilization_factorNumeric. Mutation rate multiplier for stable zones.
exploration_factorNumeric. Mutation rate multiplier for exploration zones.
assess()
Assess the microenvironment around each antibody.
Microenvironment$assess( repertoire, X, affinityFunc = "gaussian", affinityParams = list(alpha = 1, c = 1, p = 2) )
repertoireAn ImmuneRepertoire object.
XNumeric matrix of training data (n x d).
affinityFuncCharacter. Affinity function.
affinityParamsList. Affinity parameters.
Named list with densities, zones, and mutation_modifiers per antibody.
format()
Format a short summary, one element per line. Used by
print().
Microenvironment$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
Microenvironment$clone(deep = FALSE)
deepWhether to make a deep clone.
# Assess microenvironment around antibodies data(iris) X <- as.matrix(iris[, 1:4]) me <- Microenvironment$new() rep <- ImmuneRepertoire$new(X[sample(150, 15), ]) env <- me$assess(rep, X) table(env$zones) # stable, explore, boundary env$mutation_modifiers # per-antibody rate scaling# Assess microenvironment around antibodies data(iris) X <- as.matrix(iris[, 1:4]) me <- Microenvironment$new() rep <- ImmuneRepertoire$new(X[sample(150, 15), ]) env <- me$assess(rep, X) table(env$zones) # stable, explore, boundary env$mutation_modifiers # per-antibody rate scaling
After running bHIVE (or within honeycombHIVE), you have a set of
final antibody positions (A) in feature space. This function refines those
prototypes by iterating over the data points assigned to each antibody and
applying gradient-based updates using a user-chosen loss function and optimizer.
refineB( A, X, y = NULL, assignments, task = c("clustering", "classification"), loss = c("categorical_crossentropy", "binary_crossentropy", "kullback_leibler", "cosine", "mae"), steps = 5, lr = 0.01, push_away = TRUE, verbose = TRUE, optimizer = c("sgd", "momentum", "adagrad", "adam", "rmsprop"), momentum_coef = 0.9, beta1 = 0.9, beta2 = 0.999, rmsprop_decay = 0.9, epsilon = 1e-08 )refineB( A, X, y = NULL, assignments, task = c("clustering", "classification"), loss = c("categorical_crossentropy", "binary_crossentropy", "kullback_leibler", "cosine", "mae"), steps = 5, lr = 0.01, push_away = TRUE, verbose = TRUE, optimizer = c("sgd", "momentum", "adagrad", "adam", "rmsprop"), momentum_coef = 0.9, beta1 = 0.9, beta2 = 0.999, rmsprop_decay = 0.9, epsilon = 1e-08 )
A |
Numeric matrix (nAb x d) of antibody/prototype positions. |
X |
Matrix or data frame (nSamples x d) of feature data. |
y |
Optional. Factor (classification) or NULL (clustering). |
assignments |
Vector (length = nSamples) giving the antibody each
sample belongs to. Numeric values are row indices of |
task |
One of |
loss |
One of |
steps |
Integer. How many gradient steps to run. |
lr |
Numeric. Learning rate for each update. |
push_away |
Logical (for classification). Whether to push prototypes away from differently-labeled samples. |
verbose |
Logical. If |
optimizer |
One of |
momentum_coef |
Numeric. Momentum coefficient (used if |
beta1 |
Numeric. Exponential decay rate for the first moment estimates (used in Adam). |
beta2 |
Numeric. Exponential decay rate for the second moment estimates (used in Adam). |
rmsprop_decay |
Numeric. Decay factor for the squared gradient moving average (used in RMSProp). |
epsilon |
Numeric. A small constant for numerical stability. |
The user must provide:
- A numeric matrix A of antibody/prototype positions (nAb x nFeatures).
- A numeric matrix/data frame X of data (nSamples x nFeatures).
- Optional y for classification. If task="clustering",
y can be NULL or ignored.
- An integer or character vector assignments (length=nSamples) giving the
antibody index (or label) to which each data point is assigned.
## Available Losses
### Classification (factor y) - **"categorical_crossentropy"**: Pull prototypes toward data points if they share the antibody's dominant label; push away otherwise. - **"binary_crossentropy"**: Similar to categorical CE, but we interpret factor y as binary (two classes). Pull for same label, push for different label. - **"kullback_leibler"**: Very rough approach that treats "dominant label vs. others" as p and q distributions, pushing/pulling prototypes. - **"cosine"**: Interpreted as trying to maximize cosine similarity for same-label points and minimize for different-label points. - **"mae"**: Sign-based pull/push.
## Available Optimizers - **"sgd"**: Basic stochastic gradient descent. - **"momentum"**: SGD with momentum. - **"adagrad"**: Adaptive gradient descent. - **"adam"**: Adaptive moment estimation. - **"rmsprop"**: Root Mean Square Propagation.
This function performs gradient-based updates on each antibody using the selected loss function.
Depending on the chosen optimizer, it may use plain SGD, momentum-based updates, Adagrad,
Adam, or RMSProp.
Updated matrix A of shape (nAb x d).
data(iris) X <- as.matrix(iris[, 1:4]) y <- iris$Species res <- bHIVE(X, y, task = "classification", nAntibodies = 10, maxIter = 5, verbose = FALSE) # antibody_index gives the antibody (row of res$antibodies) that labeled # each sample A_refined <- refineB(res$antibodies, X, y = y, assignments = res$antibody_index, task = "classification", loss = "categorical_crossentropy", optimizer = "adam", steps = 3, lr = 0.01, verbose = FALSE) dim(A_refined)data(iris) X <- as.matrix(iris[, 1:4]) y <- iris$Species res <- bHIVE(X, y, task = "classification", nAntibodies = 10, maxIter = 5, verbose = FALSE) # antibody_index gives the antibody (row of res$antibodies) that labeled # each sample A_refined <- refineB(res$antibodies, X, y = y, assignments = res$antibody_index, task = "classification", loss = "categorical_crossentropy", optimizer = "adam", steps = 3, lr = 0.01, verbose = FALSE) dim(A_refined)
Somatic Hypermutation Engine implementing five biologically- inspired mutation strategies for the bHIVE artificial immune system.
The five strategies are:
Classic random Gaussian noise. Mutation rate = (1-affinity) * decay^(iter-1). This is the original bHIVE behavior.
AIRS-style affinity-proportional mutation. Rate = c * exp(-affinity / T). From Watkins & Timmis (AIRS2), achieving 50% better data reduction than uniform.
Feature-importance-weighted mutation. Features with higher gradient magnitude mutate more, analogous to AID targeting WRCY motifs in real SHM.
Energy-budget-constrained mutation. Total mutation magnitude bounded by E = E_0 * (1-affinity)^2, inspired by Kleinstein's E_SHM ~ N_Mut^2 model.
Per-feature adaptive mutation rate with moment tracking, directly implementing SHM as the Adam optimizer.
An R6Class generator. SHMEngine$new()
returns an SHMEngine object.
methodCharacter. One of "uniform", "airs", "hotspot", "energy", "adaptive".
paramsNamed list of method-specific parameters.
m1_stateFirst moment state matrix (for adaptive method).
m2_stateSecond moment state matrix (for adaptive method).
new()
Create a new SHMEngine.
SHMEngine$new( method = "uniform", decay = 1, mutationMin = 0.01, c_rate = 1, temperature = 0.5, E_0 = 1, base_rate = 0.1, beta1 = 0.9, beta2 = 0.999, adam_epsilon = 1e-08 )
methodCharacter. Mutation strategy.
decayNumeric. Per-iteration mutation rate decay (uniform method).
mutationMinNumeric. Minimum mutation rate floor.
c_rateNumeric. Scaling constant (airs method).
temperatureNumeric. Temperature parameter (airs method).
E_0Numeric. Energy budget base (energy method).
base_rateNumeric. Base mutation rate (hotspot, adaptive methods).
beta1Numeric. First moment decay (adaptive method, like Adam).
beta2Numeric. Second moment decay (adaptive method, like Adam).
adam_epsilonNumeric. Numerical stability (adaptive method).
init_state()
Initialize internal state for adaptive method.
SHMEngine$init_state(nAntibodies, nFeatures)
nAntibodiesInteger. Number of antibodies.
nFeaturesInteger. Number of features.
The engine, invisibly, with its moment state set.
reset_state()
Reset moment states (e.g., after suppression changes antibody count).
SHMEngine$reset_state(nAntibodies, nFeatures, kept_idx = NULL)
nAntibodiesInteger. New number of antibodies.
nFeaturesInteger. Number of features.
kept_idxInteger vector. Indices of antibodies that were kept.
The engine, invisibly, with its moment state reset or subset.
format()
Format a short summary, one element per line. Used by
print().
SHMEngine$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
SHMEngine$clone(deep = FALSE)
deepWhether to make a deep clone.
# Create different SHM engines shm_uniform <- SHMEngine$new(method = "uniform") shm_adaptive <- SHMEngine$new(method = "adaptive", base_rate = 0.1) shm_airs <- SHMEngine$new(method = "airs", temperature = 0.3) print(shm_adaptive)# Create different SHM engines shm_uniform <- SHMEngine$new(method = "uniform") shm_adaptive <- SHMEngine$new(method = "adaptive", base_rate = 0.1) shm_airs <- SHMEngine$new(method = "airs", temperature = 0.3) print(shm_adaptive)
Performs hyperparameter tuning for the bHIVE algorithm over a grid of hyperparameter values or an externally provided data frame of parameter combinations. Evaluates each combination using different metrics:
swarmbHIVE( X, y = NULL, task = c("clustering", "classification"), grid, metric = NULL, maxIter = 50, BPPARAM = SerialParam(), verbose = TRUE )swarmbHIVE( X, y = NULL, task = c("clustering", "classification"), grid, metric = NULL, maxIter = 50, BPPARAM = SerialParam(), verbose = TRUE )
X |
A numeric matrix or data frame of input features (rows = observations, columns = features). |
y |
Optional. A factor target vector for classification.
If |
task |
Character. One of |
grid |
A data frame specifying the hyperparameter combinations, one
row per combination. Any column named after a |
metric |
Character. Name of the evaluation metric. Options:
|
maxIter |
Integer. Maximum iterations for each |
BPPARAM |
Character. A BiocParallel::bpparam() object that can be used
for parallelization. The function supports |
verbose |
Logical. If |
- **Classification**: "accuracy", "balanced_accuracy", "f1", "kappa" - **Clustering**: "silhouette", "davies_bouldin", or "calinski_harabasz"
**Note**: Some metrics require additional packages or assumptions (e.g., multi-class classification for "f1" is calculated as a macro-average).
A list:
best_params: A list (row) of the best hyperparameters.
results: A data frame with the full grid search results,
including the metric_value for each combination.
data(iris) X <- as.matrix(iris[, 1:4]) y <- iris$Species # classification # Define hyperparameter grid grid <- expand.grid( nAntibodies = c(10, 20), beta = c(3, 5), epsilon = c(0.01, 0.05) ) # Perform hyperparameter tuning for classification tuning_results <- swarmbHIVE(X = X, y = y, task = "classification", grid = grid, metric = "balanced_accuracy", maxIter = 10) # For clustering with silhouette set.seed(42) X_clust <- matrix(rnorm(100 * 5), ncol = 5) grid_clust <- expand.grid(nAntibodies = c(5, 10), beta = c(3, 5), epsilon = c(0.01, 0.05)) res_clust <- swarmbHIVE(X_clust, task = "clustering", grid = grid_clust, metric = "silhouette") res_clust$best_paramsdata(iris) X <- as.matrix(iris[, 1:4]) y <- iris$Species # classification # Define hyperparameter grid grid <- expand.grid( nAntibodies = c(10, 20), beta = c(3, 5), epsilon = c(0.01, 0.05) ) # Perform hyperparameter tuning for classification tuning_results <- swarmbHIVE(X = X, y = y, task = "classification", grid = grid, metric = "balanced_accuracy", maxIter = 10) # For clustering with silhouette set.seed(42) X_clust <- matrix(rnorm(100 * 5), ncol = 5) grid_clust <- expand.grid(nAntibodies = c(5, 10), beta = c(3, 5), epsilon = c(0.01, 0.05)) res_clust <- swarmbHIVE(X_clust, task = "clustering", grid = grid_clust, metric = "silhouette") res_clust$best_params
V(D)J gene library initialization for antibody populations. Instead of random sampling, antibodies are generated by combinatorial assembly of gene segments, mimicking the V(D)J recombination that generates antibody diversity in real immune systems.
The feature space is decomposed into V, D, and J segments (subsets of dimensions). Each segment is discretized into "alleles" by clustering. New antibodies are generated by combinatorial sampling of one allele from each segment, producing structured coverage of the data manifold.
Methods:
"pca": PCA components define gene segments
"cluster": k-means within dimension groups creates alleles
"random_partition": Random feature grouping
An R6Class generator. VDJLibrary$new()
returns a VDJLibrary object.
nVNumber of V gene segments.
nDNumber of D gene segments.
nJNumber of J gene segments.
methodDecomposition method.
libraryThe computed gene library (list of allele matrices).
new()
Create a new VDJLibrary.
VDJLibrary$new(nV = 10, nD = 5, nJ = 4, method = "pca")
nVInteger. Number of V gene alleles.
nDInteger. Number of D gene alleles.
nJInteger. Number of J gene alleles.
methodCharacter. "pca", "cluster", or "random_partition".
build()
Build the gene library from training data.
VDJLibrary$build(X)
XNumeric matrix (n x d).
Invisible self.
generate()
Generate antibodies by combinatorial V(D)J assembly.
VDJLibrary$generate(nAntibodies, X)
nAntibodiesInteger. Number of antibodies to generate.
XNumeric matrix. Training data (used to build library if needed).
Numeric matrix (nAntibodies x d).
format()
Format a short summary, one element per line. Used by
print().
VDJLibrary$format(...)
...Not used.
A character vector.
clone()
The objects of this class are cloneable with this method.
VDJLibrary$clone(deep = FALSE)
deepWhether to make a deep clone.
# Generate antibodies via V(D)J combinatorial assembly data(iris) X <- as.matrix(iris[, 1:4]) vdj <- VDJLibrary$new(nV = 5, nD = 3, nJ = 3, method = "pca") A <- vdj$generate(20, X) dim(A) # 20 x 4 print(vdj)# Generate antibodies via V(D)J combinatorial assembly data(iris) X <- as.matrix(iris[, 1:4]) vdj <- VDJLibrary$new(nV = 5, nD = 3, nJ = 3, method = "pca") A <- vdj$generate(20, X) dim(A) # 20 x 4 print(vdj)
Plots the data together with the prototypes learned by bHIVE
or honeycombHIVE. One or more layers can be shown, faceted by
layer:
visualizeHIVE( result, X = NULL, plot_type = c("scatter", "boxplot", "violin", "density"), feature = NULL, transform = TRUE, transformation_method = c("PCA", "UMAP", "tSNE", "none"), title = "HIVE Results", layer = 1, task = NULL, ... )visualizeHIVE( result, X = NULL, plot_type = c("scatter", "boxplot", "violin", "density"), feature = NULL, transform = TRUE, transformation_method = c("PCA", "UMAP", "tSNE", "none"), title = "HIVE Results", layer = 1, task = NULL, ... )
result |
A list produced by |
X |
A numeric matrix or data frame of the original input features,
with the observations in the same order as the input to |
plot_type |
Character string specifying the type of plot to generate. Options are:
|
feature |
Optional. For |
transform |
Logical. If |
transformation_method |
Character. The method used for dimensionality
reduction. Options are |
title |
Character. Title for the plot. |
layer |
Integer vector indicating which layer(s) of the result to visualize.
For bHIVE outputs, default is |
task |
Character, |
... |
Additional arguments passed to the dimensionality reduction:
|
"scatter": The observations, colored by cluster or class,
with the prototypes drawn on top in the same coordinates. When X
has more than two columns and transform is TRUE, a
dimensionality reduction is fitted to X and the prototypes are
projected into it.
"boxplot", "violin": A selected feature by group, with
the prototypes' values overlaid.
"density": Density of a selected feature by group, with the
prototypes' values marked.
For scatterplots the reduction is "PCA", "UMAP",
"tSNE" or "none". PCA and UMAP are fitted to X only and
the prototypes are placed with the fitted model's predict() method,
so both share one coordinate system. UMAP's projection of new points is an
approximation. tSNE has no such projection, so the data and prototypes are
embedded together and the prototypes take a small part in shaping the
layout.
The prototypes drawn are, for a bHIVE() result, the antibodies in
original feature units (antibodies_unscaled), and for a
honeycombHIVE() layer, the collapsed prototypes that summarize
each cluster.
A ggplot object representing the visualization.
data(iris) X <- as.matrix(iris[, 1:4]) # A single bHIVE clustering, with the prototypes projected onto the PCA set.seed(1) res <- bHIVE(X, targetK = 3, maxIter = 10, verbose = FALSE) visualizeHIVE(res, X = X, plot_type = "scatter", title = "bHIVE prototypes") # Layers 1 and 2 of a honeycombHIVE hierarchy res_h <- honeycombHIVE(X = X, task = "clustering", epsilon = 0.05, layers = 3, nAntibodies = 30, beta = 5, maxIter = 10, verbose = FALSE) visualizeHIVE(res_h, X = X, plot_type = "scatter", layer = 1:2, title = "honeycombHIVE layers") # A feature by class for a classifier, with each antibody's value overlaid res_c <- bHIVE(X, y = iris$Species, maxIter = 10, verbose = FALSE) visualizeHIVE(res_c, X = X, plot_type = "violin", feature = "Petal.Length", title = "Classifier")data(iris) X <- as.matrix(iris[, 1:4]) # A single bHIVE clustering, with the prototypes projected onto the PCA set.seed(1) res <- bHIVE(X, targetK = 3, maxIter = 10, verbose = FALSE) visualizeHIVE(res, X = X, plot_type = "scatter", title = "bHIVE prototypes") # Layers 1 and 2 of a honeycombHIVE hierarchy res_h <- honeycombHIVE(X = X, task = "clustering", epsilon = 0.05, layers = 3, nAntibodies = 30, beta = 5, maxIter = 10, verbose = FALSE) visualizeHIVE(res_h, X = X, plot_type = "scatter", layer = 1:2, title = "honeycombHIVE layers") # A feature by class for a classifier, with each antibody's value overlaid res_c <- bHIVE(X, y = iris$Species, maxIter = 10, verbose = FALSE) visualizeHIVE(res_c, X = X, plot_type = "violin", feature = "Petal.Length", title = "Classifier")