// H2Learn — Matching Algorithms / Explainable Logic (function() { const D = window.H2Data; const { useState } = React; const AlgorithmsScreen = () => { const [selected, setSelected] = useState('sim'); const algo = D.ALGORITHMS.find(a => a.key === selected) || D.ALGORITHMS[0]; return (
{/* hero */}
How matching works

Nine algorithms, one explainable graph.

Every match in H2Learn is built from explicit signals you can audit. No black-box ranking — just nine well-named algorithm families that compare your questionnaire data with the rest of the ecosystem.

The pipeline
{[ {n:'01', l:'Questionnaire', d:'You answer guided questions.'}, {n:'02', l:'Normalize', d:'Answers become structured entities + tags.'}, {n:'03', l:'Signals', d:'Profile fingerprint + needs/offers/bottlenecks.'}, {n:'04', l:'Match', d:'Nine algorithms compare profiles & projects.'}, {n:'05', l:'Explain', d:'Every edge stores its reason.'}, ].map(s => (
{s.n}
{s.l} {s.d}
))}
{/* === Algorithm grid === */}

Algorithm families

Click any card to see signals, formula, and a worked example.
Levels of explanation Algorithm reference (PDF)
{D.ALGORITHMS.map(a => ( setSelected(a.key)}/> ))}
{/* === Selected algorithm detail === */}
Algorithm · {algo.key}

{algo.name}

{algo.plain}

Formula family
{algo.formula}
Signals it reads
{algo.signals.map(s => {s})}
Where in the questionnaire
{sourceMap[algo.key].map((s,i) => (
{s}
))}
{/* === Edge anatomy === */}
Anatomy of one edge

Every relationship in the graph stores its reason

What every edge contains
{[ ['source', 'Origin node id'], ['target', 'Destination node id'], ['type', 'One of 8 relationship types'], ['strength', '0–1 normalized score'], ['confidence', '0–1 system confidence'], ['signals[]', 'Per-signal score + weight'], ['explanation', 'Plain-English summary'], ['evidence[]', 'Linked questionnaire answers'], ['generatedAt', 'Timestamp · provenance'], ['curatorReviewed', 'true / false / pending'], ].map(([k,v]) => (
{k} {v}
))}
{/* === Two levels of explanation === */}
Level 1

User-friendly explanation

Plain-English, action-oriented. "Sara matches HYDRO-NL because she offers exactly the membrane test method they need, and they share PEM expertise."

Default for every match card, network drawer, and dashboard recommendation.
Level 2 · expandable

Technical details

Optional expandable section for analysts and curators. Shows formulas, signal weights, edge metadata, and source data.

cosine(fp_a, fp_b) · 0.4
+ jaccard(domains_a, domains_b) · 0.15
+ needoffer(a, b) · 0.30
+ project_compat(a, b) · 0.15
location.hash='match'}>See it in action — open a match
); }; const sourceMap = { sim: ['Q-knowledge — domains/subdomains', 'Q-weights — 100-point allocation', 'Q-fingerprint (derived)'], overlap: ['Q-domains', 'Q-methods', 'Q-sectors'], needoffer: ['Q-needs · open resources you lack', 'Q-offers · resources you can share', 'Q-challenges · missing resource fields'], project: ['Q-project — stage', 'Q-project — TRL', 'Q-project — scale & application'], antidup: ['Q-challenges', 'Q-bottlenecks · severity 1–5', 'Q-bottlenecks · type (internal/external)'], uncertain: ['Q-uncertainties · domain', 'Q-uncertainties · planning horizon', 'Q-confidence levels'], bridge: ['Q-orientation · cross-sector ties', 'Q-partners — types', 'derived bridge centrality'], method: ['Q-methods — active toolkit', 'Q-challenges — required method'], central: ['Graph adjacency (derived)', 'Cross-cluster edges (derived)', 'Eigenvector centrality (derived)'], }; // ============ Algo card ============ const AlgoCard = ({a, on, onClick}) => ( ); // ============ Worked examples (per algo) ============ const WorkedExample = ({algoKey}) => { if (algoKey === 'sim') return ; if (algoKey === 'needoffer') return ; if (algoKey === 'antidup') return ; return ; }; const ExSim = () => { const sara = D.PEOPLE.find(p => p.id === 'p_sara').fingerprint; const lies = D.PEOPLE.find(p => p.id === 'p_liesbeth').fingerprint; const allDomains = [...new Set([...sara.map(s=>s.d), ...lies.map(s=>s.d)])]; return (
Worked example · Sara × Liesbeth
{allDomains.map(d => { const sw = sara.find(x => x.d === d)?.w || 0; const lw = lies.find(x => x.d === d)?.w || 0; const max = 50; return (
{d}
{sw}
{lw}
); })}
cosine ≈ 0.92 contributes 40% of similarity score
); }; const ExNeedOffer = () => (
Worked example · Sara × HYDRO-NL
HYDRO-NL · need
Membrane durability data
From Q-challenges · "missing resource"
Sara · offer
Membrane test method
From Q-offers · open resource
match strength · 0.95
Token overlap on "membrane" + "durability" is 100%. The need-vs-offer alignment alone explains most of the match score.
); const ExAntiDup = () => (
Worked example · Bram × Liesbeth
Both teams hitting the same wall
Challenge similarity 0.90
Bottleneck similarity 0.88
Product 0.90 × 0.88 0.79 > τ (0.6) ✓
Both flagged "membrane durability protocols" as their core challenge and "pilot data sharing" as their main external bottleneck. Coordination here would reduce parallel work.
); const ExGeneric = ({algoKey}) => { const samples = { overlap: { a:'Sara', b:'Liesbeth', shared:['PEM','Membrane','LCA'], score: '5/5 domains'}, project: { a:'GreenH2-PEM (TRL 4)', b:'HYDRO-NL (TRL 5)', shared:['Pilot scale','NL region'], score: 'compat 0.78'}, uncertain:{ a:'Sara', b:'Nora', shared:['simulation-field gap','3-yr horizon'], score: 'overlap 0.80'}, bridge: { a:'Iteke', b:'Lori', shared:['research↔education','industry↔policy'], score: 'bridge 0.92 / 0.88'}, method: { a:'Nora · digital twin', b:'HYDRO-NL · model gap', shared:['simulation','TEA'], score:'transfer 0.85'}, central: { a:'Iteke', b:'graph', shared:['betweenness','degree'], score:'top decile'}, }; const s = samples[algoKey] || samples.overlap; return (
Worked example · {s.a} × {s.b}
{s.shared.map(x => {x})}
Result {s.score}
); }; const Legend2 = ({c, l}) => (
{l}
); // ============ Edge anatomy: visual edge with all metadata ============ const EdgeAnatomy = () => { const m = D.MATCHES[0]; // Sara × HYDRO-NL return (
{/* edge */} {/* nodes */} SA Sara Arif person HN HYDRO-NL Pilot project {/* annotations */} type · Complementarity strength 0.88 confidence 0.92
{`{ source: "p_sara", target: "pj_hydronl", type: "Complementarity", strength: 0.88, confidence: 0.92, signals: [ {needOffer: 0.95}, {subdomain: 0.78}, ... ], explanation: "${m.summary.slice(0, 60)}…", curatorReviewed: true, generatedAt: "2026-03-14" }`}
); }; Object.assign(window, { AlgorithmsScreen }); })();