Skip to content

Latest commit

 

History

148 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Popper

A compiler for scientific claims.

Popper takes a hypothesis, compiles it into a signed causal chain, checks the arithmetic against a curated database of molecular interactions, and returns a verdict that does not depend on a language model's opinion.

Disclosure

Read this before the rest.

  • The Bisociation Engine pre-existed this project. The 3D graph, the PubChem and DisGeNET clients, the LLM decomposition, the split and merged views and the input screen were all built beforehand. What is new is the verifier: the signed network, the solver, the compiler that replaced free-text hypothesis generation, and the interface that colours edges by arithmetic instead of by confidence.
  • Tier 4 is a mock. Every assay name, dollar figure and week count in src/engine/tier4.js was typed by hand. No CRO was contacted, no quote was obtained, and Tier4Estimate.isMock is true on every record.
  • One edge in every chain comes from a language model. The drug-to-target sign is extracted from PubChem pharmacology text by gpt-4o-mini. Every subsequent hop comes from OmniPath. The receipt panel's Audit section names that edge and shows the source span it was taken from.
  • Protein complexes are dropped. OmniPath models complexes as compound nodes, and 75,716 of 177,458 interaction rows have a complex at one end. Walking them correctly means modelling how a signal enters and leaves a complex, which this does not attempt. Pathways that route only through a complex are invisible, which is why metformin and AMPK is not a usable pair: AMPK reaches OmniPath only as PRKAA1_PRKAA2_PRKAB1_....

What the verdict means

The claim "drug D treats disease E through gene G" becomes a product of signs. Inhibition is −1, activation is +1, unknown is 0. Multiply along the chain and compare with what the disease requires: if gene G is elevated in the disease, therapy must push it down, so the required sign is −1.

Verdict Meaning
CONSISTENT Every decisive path agrees with the required direction
REFUTED Every decisive path pushes the disease gene the wrong way
CONTESTED Paths disagree; the counts are shown rather than averaged
UNDETERMINED No signed path within four hops, or every path crosses an unknown edge

CONSISTENT is not proof. It means the claim survived the check, which is the only thing falsification ever offers. Verdicts are never averaged into a score, and Tiers 2 through 4 annotate the verdict but never overrule it — Hypothesis.finalVerdict is always tier1.verdict.

Limitations

  • A verdict is only as good as OmniPath. Coverage is uneven. A gene with few curated signed edges returns UNDETERMINED because the database is thin there, not because the biology is unknown to science.
  • Sign conflicts become unknown, not majority-ruled. Where two resources disagree on an interaction's direction, the edge is dropped to 0 and poisons any path through it. 131 edges resolved this way.
  • Only the shortest routes are judged. Enumerating every route up to the depth limit found paths of both signs for almost every pair, so nearly everything came out CONTESTED at around 55% and the verdict decided nothing. The solver therefore judges only shortest-length routes, which is also the more defensible reading: a three-hop detour through a transcriptional hub is not the mechanism anyone is asserting. Longer routes are neither counted nor shown.
  • Edges with fewer than three publications are not walked at all. They are excluded from traversal rather than down-ranked, because thousands of single-publication interactions are what let the network reach anything from anything. A real but thinly curated mechanism is therefore invisible, and the floor also changes which route counts as shortest.
  • Three hops maximum, 200 paths maximum. Longer or wider mechanisms are not explored, and a truncated enumeration is labelled as capped.
  • Directional claims only. "Gene G is elevated in disease E" is a coarse summary of a tissue, timepoint and patient population that Popper does not model.
  • Nothing here is medical advice, and no output is evidence that a drug works.

Bisociation Engine (the pre-existing base)

Engineering creativity through cross-domain pattern matching.

demo

The idea

Can AI be creative? If creativity is the collision of patterns across unrelated domains, then yes -- and it can be engineered. Arthur Koestler called this bisociation: the moment two previously unconnected frames of reference intersect and produce something neither could alone. Every major scientific breakthrough follows this shape. Penicillin, Velcro, CRISPR -- accidents where knowledge from one field crashed into another.

This engine mechanizes that collision. It takes a drug and a disease, decomposes each into a graph of real biomedical properties -- mechanisms, protein targets, pathways, genes -- and then systematically connects every property of the drug to every property of the disease. At each intersection, an LLM generates a novel repurposing hypothesis grounded in actual biology. The result is a combinatorial search over the space between two domains, surfacing connections a human researcher might take years to notice.

Drug repurposing is the first application, but the architecture is domain-agnostic. Swap the data sources and you can bisociate across materials science, synthetic chemistry, or any field with structured knowledge. Connect it to an automated testing pipeline -- generate hypotheses, run the strong ones through wet-lab or simulation, feed results back -- and you have a system that doesn't just suggest. It discovers. That closed loop is what real knowledge-creating AI looks like.

How it works

  1. Enter a drug name and a disease name
  2. The app fetches real biomedical data from PubChem (mechanisms, targets, pharmacology). Optionally, DisGeNET gene-disease associations ground the disease side
  3. An LLM decomposes both into structured graph nodes -- each a real biological entity
  4. Two interactive 3D force-directed graphs render side by side. Click either to expand full-screen
  5. Trigger bisociation -- every drug node connects to every disease node
  6. Press Compile. Each cross-edge whose endpoints resolve to genes in the signed network is compiled into a CompiledClaim, then solved
  7. Edges recolour one at a time as verdicts land: cyan consistent, oxide refuted, ochre contested, slate undetermined or untested
  8. Click any edge for its receipt: the sign chain, the arithmetic, the PMIDs behind each hop, and the model-extracted edge quarantined in Audit

Steps 1 through 5 are the original Bisociation Engine. Steps 6 through 8 are Popper.

Tech stack

  • React 19 (Vite)
  • react-force-graph-3d + Three.js (WebGL)
  • Tailwind CSS v4
  • OpenAI API (gpt-4o-mini)
  • PubChem PUG REST / PUG View API
  • DisGeNET REST API (optional, for grounded disease decomposition)

Getting started

git clone <repo-url>
cd bissociation_engine
npm install

Create a .env file. The name is deliberately un-prefixed: a VITE_-prefixed variable is inlined into the browser bundle, which is how the key used to leak.

OPENAI_API_KEY=sk-your-key-here

Run the dev server. The /api/* routes are served by Vite middleware in development and by Vercel functions in production, from the same files in api/.

npm run dev

Other scripts:

npm test           # solver and selection unit tests
npm run typecheck  # tsc --noEmit against the frozen contract
npm run build:network   # regenerate public/omnipath.json from OmniPath

The signed network is committed, so a clone does not need to rebuild it. OmniPath is never queried at demo time.

DisGeNET (optional): On the input screen, toggle to "DisGeNET + LLM" and enter your API key (free at disgenet.org). The key is stored in localStorage. When enabled, gene-disease associations are fetched and injected into the LLM prompt so disease nodes are grounded in real association data rather than model priors alone.

Project structure

api/
├── llm.js                 # OpenAI relay; holds the key server-side
└── proxy.js               # GET relay for PubChem, ClinicalTrials, DisGeNET
scripts/
└── build-network.mjs      # OmniPath TSV -> public/omnipath.json
src/
├── types.ts               # The frozen contract: vocabulary and arithmetic
├── engine/                # Pure, no network, no LLM
│   ├── paths.ts           # Bounded path enumeration with reachability pruning
│   ├── solve.ts           # CompiledClaim -> Tier1Result
│   ├── explain.ts         # Template verdict sentences, never LLM-written
│   ├── select.ts          # Which cross-edges are groundable, ranked
│   ├── network.js         # Loads the committed omnipath.json
│   ├── tier4.js           # Mock assay estimates
│   └── pipeline.js        # compile -> solve -> price, streamed
├── api/
│   ├── compile.js         # The LLM's only job: emit a CompiledClaim
│   ├── score.js           # The old confidence signal, kept for contrast
│   ├── trials.js          # Tier 3 prior art
│   ├── llm.js             # Decomposition into graph nodes
│   ├── pubchem.js         # PubChem name -> CID and compound view
│   ├── parsePubChem.js    # PUG View section tree parser
│   └── disgenet.js        # DisGeNET gene-disease associations
├── components/
│   ├── SignChain.jsx      # The claim as its arithmetic
│   ├── ReceiptPanel.jsx   # Why an edge is the colour it is
│   ├── LadderRail.jsx     # The four tiers for one hypothesis
│   ├── MergedView.jsx     # Merged graph, recoloured by verdict
│   ├── BioGraph.jsx       # 3D force graph with glowing nodes
│   ├── SplitView.jsx      # Side-by-side drug/disease graphs
│   ├── GraphContextLabels.jsx
│   ├── AmbientMeshBackground.jsx
│   └── AnalysisLoadingOverlay.jsx
├── ui/verdict.js          # One definition of what each verdict looks like
├── utils/buildGraphData.js
├── App.jsx
└── main.jsx

src/types.ts is the contract both this app and the benchmark import. Neither reimplements multiplySigns, classifyNetSign or verdictFromCounts, so the two cannot disagree about what a sign product means.

Beyond drug repurposing

This engine is a proof of concept for a general principle: structured cross-domain search, powered by LLMs, over real data. Replace PubChem with a materials database, or DisGeNET with a pathway atlas, and the same decompose-connect-hypothesize loop applies. Pair it with automated experimental validation and you close the loop entirely -- AI that generates hypotheses, tests them, and refines its model. That is the direction this points toward.

License

MIT

About

AI-driven bisociation engine for drug repurposing that decomposes drugs and diseases into interactive 3D knowledge graphs via PubChem and DisGeNET APIs, then systematically cross-connects every property pair to generate and score novel therapeutic hypotheses using parallel LLM inference

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages