Note
Go to the end to download the full example code.
NeuroSynth Query in SQUALL Controlled English.#
Reproduces the NeuroSynth forward model — P(Activation | Term = ‘auditory’) — using SQUALL controlled natural language instead of the IR builder DSL.
The four logic rules plus an obtain query are expressed as plain English
sentences and executed via
execute_squall_program(), which
returns the query result directly when an obtain clause is present. Compare
with NeuroLang Example based Implementing a NeuroSynth Query which
writes identical rules using with nl.scope as e:.
The SQUALL program
define as Activation every Peak_reported (?i; ?j; ?k; ?s)
such that ?s is a Selected_study.
define as Term_association every Term_in_study_tfidf (?s; ?t; ?tfidf)
such that ?s is a Selected_study.
define as Activation_given_term with probability
every Activation (?i; ?j; ?k; _)
conditioned to every Term_association ?t that is 'auditory'.
define as Activation_given_term_image
every Agg_create_region_overlay of the Activation_given_term (?i; ?j; ?k; ?p).
obtain every Activation_given_term_image (?x).
import warnings
warnings.filterwarnings("ignore")
from pathlib import Path
from typing import Iterable
import nibabel
import nilearn.datasets
import nilearn.image
import nilearn.plotting
import numpy as np
from neurolang import ExplicitVBROverlay, NeurolangPDL
from neurolang.frontend.neurosynth_utils import get_ns_mni_peaks_reported
Set the data directory and load the MNI T1 atlas resampled to 4 mm voxels.
data_dir = Path.home() / "neurolang_data"
mni_t1 = nibabel.load(
nilearn.datasets.fetch_icbm152_2009(data_dir=str(data_dir / "icbm"))["t1"]
)
mni_t1_4mm = nilearn.image.resample_img(mni_t1, np.eye(3) * 4)
nl = NeurolangPDL()
@nl.add_symbol
def agg_create_region_overlay(
i: Iterable, j: Iterable, k: Iterable, p: Iterable
) -> ExplicitVBROverlay:
"""Aggregate (i,j,k,probability) rows into a brain overlay image."""
mni_coords = np.c_[i, j, k]
return ExplicitVBROverlay(
mni_coords, mni_t1_4mm.affine, p, image_dim=mni_t1_4mm.shape
)
Register peaks, study IDs, and term–study associations as extensional facts. Relation names are lowercase so they match SQUALL’s case-folding convention.
peak_data = get_ns_mni_peaks_reported(data_dir)
ijk_positions = np.round(
nibabel.affines.apply_affine(
np.linalg.inv(mni_t1_4mm.affine),
peak_data[["x", "y", "z"]].values.astype(float),
)
).astype(int)
peak_data["i"] = ijk_positions[:, 0]
peak_data["j"] = ijk_positions[:, 1]
peak_data["k"] = ijk_positions[:, 2]
peak_data = peak_data[["i", "j", "k", "id"]]
nl.add_tuple_set(peak_data, name="peak_reported")
study_ids = nl.load_neurosynth_study_ids(data_dir, "study")
nl.add_uniform_probabilistic_choice_over_set(
study_ids.value, name="selected_study"
)
nl.load_neurosynth_term_study_associations(
data_dir, "term_in_study_tfidf", tfidf_threshold=1e-3
)
Four
definesentences plus oneobtainclause replace the entirewith nl.scope as e:block and the separatenl.query()call.
such that ?s is a Selected_study— existential study filter
?t that is 'auditory'— string equality on term
with probability … conditioned to— MARG conditional probability
(?i; ?j; ?k; _)—_drops the study column from the conditioned head (anonymous wildcard)
of the Activation_given_term (?i;?j;?k;?p)— explicit tuple label so the aggregation functor receives all four columns (i, j, k, probability)
obtain every Activation_given_term_image (?x)— runs only this queryNote:
?tfidfbinds the TF-IDF weight column but is absent from the rule head (projected away). Anonymous wildcards are supported in tuple labels (e.g.(?i; ?j; ?k; _)on lines below — each_creates a fresh variable that is matched but dropped from the rule head).
squall_program = """
define as Activation every Peak_reported (?i; ?j; ?k; ?s)
such that ?s is a Selected_study.
define as Term_association every Term_in_study_tfidf (?s; ?t; ?tfidf)
such that ?s is a Selected_study.
define as Activation_given_term with probability
every Activation (?i; ?j; ?k; _)
conditioned to every Term_association (?s; ?t; _) such that ?t is 'auditory'.
define as Activation_given_term_image
every Agg_create_region_overlay of the Activation_given_term (?i; ?j; ?k; ?p).
obtain every Activation_given_term_image (?x).
"""
result_set = nl.execute_squall_program(squall_program)
The
obtainclause executes only the image query;result_setis the single-column result directly fromexecute_squall_program().
result_image = result_set.as_pandas_dataframe().iloc[0, 0].spatial_image()
img = result_image.get_fdata()
plot = nilearn.plotting.plot_stat_map(
result_image, threshold=np.percentile(img[img > 0], 95)
)
nilearn.plotting.show()