mixle.scientist module¶
Optional local scientific-assistant workflow.
Scientist assembles several Mixle surfaces into one offline-oriented object:
modality encoders for images and text, loaded from the local Hugging Face cache when available;
certified heads over encoder latents through
study;a substrate-backed
askworkflow using local evidence, skills, and an optional local language model;factuality and provenance checks for produced answers.
The module is intentionally optional. Heavy assets such as CLIP, MiniLM, and SmolLM2 are lazy-loaded and shared per process, and the package sets offline Hugging Face defaults at import time.
- LATENT_SPACES: dict[str, dict[str, Any]] = {'image': {'aligned_with': (), 'dim': 512, 'encoder': 'openai/clip-vit-base-patch32', 'revision': '3d74acf9a28c67741b2f4f2ea7635f0aaf6f0268', 'space_id': 'clip-vit-base-patch32.image_features/v1'}, 'text': {'aligned_with': (), 'dim': 384, 'encoder': 'sentence-transformers/all-MiniLM-L6-v2', 'revision': '1110a243fdf4706b3f48f1d95db1a4f5529b4d41', 'space_id': 'all-MiniLM-L6-v2.sentence_embedding/v1'}}
The latent space each modality encoder produces – two SEPARATE spaces, not one shared one.
encode_images()returns 512-dimensional CLIP image features;encode_texts()returns 384-dimensional embeddings from an independently trained MiniLM. There is no projection between them, no paired alignment objective, no common schema and no learned bridge, so a vector from one space carries no defined relation to a vector from the other: they cannot be compared by distance, averaged, or stacked (the dimensions do not even match). Both encoders’ docstrings used to claim they encoded into “the shared scientific latent space”; they do not. Fit a separate head per space (study()takes latents from exactly one of them), and treat any cross-space claim as requiring a bridge that would have to be trained and evidenced first.
- latent_space(modality)[source]
The representation contract for one modality’s encoder (see
LATENT_SPACES).
- scientist_asset_manifest()[source]
Return the immutable external-asset identities used by this module.
- encode_images(images, *, batch=32)[source]
CLIP ViT-B/32 image features,
(n, 512)– the real image leaf. Accepts PIL images/arrays.
- encode_texts(texts)[source]
MiniLM sentence embeddings
(n, 384)– the real text leaf.
- generate(prompt, *, max_new_tokens=96, temperature=0.0)[source]
One completion from the local LLM (SmolLM2-360M-Instruct) – the 99%-local answerer.
- class StudiedModel(head, classes, certificate, qhat, alpha, class_priors, train_seconds, provenance=<factory>)[source]
Bases:
objectA certified predictor over ONE encoder’s latents -> closed-form head, with its receipts.
Not cross-modal: it is fit on latents from a single space (see
LATENT_SPACES), andprovenance["latent_dim"]records which one it was trained in. Predicting on latents from the other encoder is a category error, not a modality it also covers.- Parameters:
- predict(z)[source]
Return the most likely class for each latent vector.
- predict_proba(z)[source]
Return normalized class probabilities for each latent vector.
- prediction_sets(z)[source]
Conformal label sets at level 1-alpha; ambiguous cases may return multiple labels.
- study(latents, labels, *, alpha=0.1, cal_frac=0.25, seed=0)[source]
Fit a CERTIFIED classifier over encoder latents: closed-form Gaussian class-conditionals + a split-conformal abstention rail. No gradient descent anywhere – the certificate proves it.
alpha(the split-conformal miscoverage level) must be in[0.0, 1.0]– the same inclusive domain asconformal_label_threshold(), which computesqhatbelow (0.0and1.0are valid boundaries, not just interior values).cal_fracmust be in(0.0, 1.0)exclusive so both the calibration and fit splits stay non-empty.latentsmust be two-dimensional(n, d)andlabelsmust align with it one-to-one.
- class EdgeArtifact(model, bytes, torch_free, family, teacher_accuracy, student_accuracy, agreement, provenance=<factory>)[source]
Bases:
objectA capability compressed to run on a constrained device: the student + its footprint + retention.
- Parameters:
- property retention: float
The share of the teacher’s accuracy retained by the edge student.
nanwhen the teacher scored zero on the validation set: the ratio’s denominator is not a valid accuracy to retain a share of, and reporting0.0there is indistinguishable from a student that genuinely retained nothing.
- distill_to_edge(teacher_predict, train_inputs, val_inputs, val_truth, *, max_bytes=500_000, torch_free=True, n_init=3, n_iter=3, seed=0)[source]
Compress a foundation capability into a torch-free edge artifact, with a retention receipt.
teacher_predictis the capability (a raw_input -> label callable – e.g. CLIP zero-shot, or a MiniLM + certified head). Its labels ontrain_inputsare the distillation target; the student learns them from the RAW inputs under a device byte budget, so the deployed artifact needs neither torch nor the foundation model. The receipt measures what survives: student accuracy vs the teacher’s, and their agreement. Boundary: this works only when the student’s own features carry the signal (text n-grams do; raw pooled pixels do NOT recover a vision foundation model).train_inputs/val_inputs/val_truthmay be any iterable (including a one-shot generator): each is materialized to a list exactly once, at entry, and that list is what every subsequent pass (teacher labeling, student training, validation metrics, provenance counts) reuses.
- class ResearchProposal(question, missing, nearest_knowledge=<factory>, options=<factory>, note='')[source]
Bases:
objectA knowledge gap made actionable: what is missing and the ranked ways to acquire it.
- Parameters:
- best()[source]
Return the highest-ranked acquisition option, if one exists.
- class Conjecture(question, sources=<factory>, status='conjecture', proposal=None)[source]
Bases:
objectA curiosity-generated question: explicitly NOT knowledge – a hypothesis with a proposed test.
- class Scientist(knowledge=None)[source]
Bases:
objectThe laptop multi-modality scientific reasoner (see module docstring).
Multi-modality, not cross-modal: it carries an image encoder and a text encoder whose latent spaces are separate and unaligned (see
LATENT_SPACES); it does not relate one modality’s latents to the other’s.- Parameters:
knowledge (Any) – a
Substrateof what it may cite (built if omitted).
ask’s abstention decision comes from retrieval confidence and the post-hoc factuality check (seeask’s own docstring), not from the local model’s self-assessed uncertainty – a 360M model’s own confidence is a poor abstention signal. Semantic-entropy gating of the kindmixle.inference.uqprovides is a real, separate mechanism in this package (ExternalModelwraps it);Scientistdeliberately uses the retrieval/factuality path instead.- learn(docs, *, source='user')[source]
Ingest documents into the citable knowledge (secrets redacted before indexing).
docsis EITHER one document (astr) or a collection of documents. A bare string is one document: iterating it directly made every character its own knowledge item, so the ordinary single-document calllearn("hello world")reported 11 documents ingested and stored["h", "e", ..., "d"]as separate citable items – destroying document structure and leaving later retrieval and provenance hanging off accidental character fragments.Any other iterable is materialized once (so a one-shot generator is not consumed by the redaction pass and then found empty by the ingest), and each item must be a string document; anything else is rejected by position rather than silently stringified into a citable “fact”. Returns the number of documents ingested.
- add_action(action)[source]
Mount a capability (a physics solver, a simulator, a fitted skill) as a reasoner action.
- Parameters:
action (Any)
- Return type:
Scientist
- ask(question, *, min_confidence=0.2)[source]
Answer with citations or abstain. The local LLM composes ONLY from retrieved evidence, and its own uncertainty is measured: an answer it cannot ground or is not confident of is withheld.
- propose(question, investigation=None)[source]
Turn an abstention into a research plan: what is missing, and ranked ways to acquire it.
This is the difference between a dead end and a scientist: an explicit “I don’t know” comes back with the acquisition options – add knowledge, run a mounted capability, fit a model to data, simulate, or delegate outward – each with what it would take and what it would settle. The ranking is EIG-per-cost over the mounted actions plus the generic acquisition strategies.
- investigate(question, **kw)[source]
ask, but an abstention comes back WITH its research proposal attached – never a bare no.
- wonder(topic=None, *, n=3, seed=0)[source]
Generate testable conjectures from what it knows – curiosity with receipts attached.
Pairs of knowledge items (optionally biased toward
topic) are handed to the local LLM with the instruction to propose a QUESTION or HYPOTHESIS connecting them. Every output is labeled a CONJECTURE and carries a proposed test (the research-proposal machinery), and is checked NOT to already be answerable from the substrate – curiosity about what it does not know, not rediscovery of what it does.
- static perceive(images)[source]
Encode images into the
"image"latent space:(n, 512)CLIP image features.This is NOT the same space
read()produces, and nothing here bridges the two – seeLATENT_SPACES. Fit a head per space; do not mix their vectors.
- static read(texts)[source]
Encode texts into the
"text"latent space:(n, 384)MiniLM sentence embeddings.This is NOT the same space
perceive()produces, and nothing here bridges the two – seeLATENT_SPACES. Fit a head per space; do not mix their vectors.
- static study(latents, labels, **kw)[source]
Fit a certified perception head over latent vectors.
- static distill_to_edge(teacher_predict, train_inputs, val_inputs, val_truth, **kw)[source]
Compress a foundation capability into a torch-free edge artifact (see
distill_to_edge()).