{
  "schemaVersion": 1,
  "slug": "correlation-calculator",
  "category": "statistics",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "8548128165bc7d12837d4f7b4a621869ab044f599e29f27ca7165ddf96b0907d",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/correlation-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "r = Σ(x − x̄)(y − ȳ) ÷ √(Σ(x − x̄)² × Σ(y − ȳ)²)",
    "vars": [
      [
        "x,y",
        "paired sample values"
      ],
      [
        "x̄,ȳ",
        "sample means"
      ],
      [
        "n",
        "number of pairs"
      ],
      [
        "r",
        "Pearson correlation"
      ]
    ],
    "note": "Pearson r uses paired finite numeric observations and is undefined when either list is constant. Inputs must have equal length (at least two); empty comma-separated fields are rejected rather than silently skipped."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const parse=s=>{const raw=String(s??'').trim();if(!raw)return null;if(raw.includes(',')){const parts=raw.split(',');if(parts.some(p=>!p.trim()))return null;return parts.flatMap(p=>p.trim().split(/\\s+/));}return raw.split(/\\s+/);};const empty={r:null,rSquared:null,covariance:null,meanX:null,meanY:null,count:null};const xr=parse(xValues),yr=parse(yValues);if(!xr||!yr||xr.length<2||xr.length!==yr.length)return{...empty,count:xr?.length??null,__error:'inputError'};const xs=xr.map(Number),ys=yr.map(Number),n=xs.length;if(xs.some(v=>!Number.isFinite(v))||ys.some(v=>!Number.isFinite(v))||n>10000)return{...empty,count:n,__error:'inputError'};const sx=xs.reduce((m,v)=>Math.max(m,Math.abs(v)),0),sy=ys.reduce((m,v)=>Math.max(m,Math.abs(v)),0);if(sx===0||sy===0)return{...empty,count:n,__error:'inputError'};const xn=xs.map(v=>v/sx),yn=ys.map(v=>v/sy),mxn=xn.reduce((a,b)=>a+b,0)/n,myn=yn.reduce((a,b)=>a+b,0)/n;let sxy=0,sxx=0,syy=0;for(let k=0;k<n;k++){const dx=xn[k]-mxn,dy=yn[k]-myn;sxy+=dx*dy;sxx+=dx*dx;syy+=dy*dy;}if(sxx===0||syy===0)return{...empty,count:n,__error:'inputError'};const r=Math.max(-1,Math.min(1,sxy/Math.sqrt(sxx*syy))),meanX=mxn*sx,meanY=myn*sy,covScaled=sxy/(n-1),covariance=covScaled===0?0:(Math.abs(covScaled)>0&&Math.abs(covScaled)>Number.MAX_VALUE/Math.min(sx,sy)/Math.max(sx,sy)?null:covScaled*Math.min(sx,sy)*Math.max(sx,sy));return{r,rSquared:r*r,covariance,meanX,meanY,count:n};",
    "inputs": [
      {
        "name": "xValues",
        "type": "text",
        "default": "1, 2, 3, 4, 5",
        "step": 1
      },
      {
        "name": "yValues",
        "type": "text",
        "default": "2, 4, 5, 4, 5",
        "step": 1
      }
    ],
    "outputs": [
      {
        "name": "r",
        "precision": 4,
        "unit": ""
      },
      {
        "name": "rSquared",
        "precision": 4,
        "unit": ""
      },
      {
        "name": "covariance",
        "precision": 4,
        "unit": ""
      },
      {
        "name": "meanX",
        "precision": 4,
        "unit": ""
      },
      {
        "name": "meanY",
        "precision": 4,
        "unit": ""
      },
      {
        "name": "count",
        "precision": 0,
        "unit": ""
      }
    ],
    "interpret": null
  }
}
