123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- const metrics = {
- alpha: { // combine sigma and bigTheta
- option: "Geometric Difference (α)",
- displayName: String.raw`\alpha`,
- displayBody: p => String.raw`
- \sigma\left(${p}\right)
- \Theta\left(${p}\right)^{
- \left(C\left(\left\{\vec{q}\right\}\right) + L\left(\left\{\vec{q}\right\}\right)\right)
- }
- `,
- evaluate: () => 0, // calculated below
- },
- sigma: { // RMS
- option: "RMS Deviation (σ)",
- displayName: String.raw`\sigma`,
- displayBody: p => String.raw`
- \sqrt{I\left(${p}\right) - 2\vec{q}\cdot\vec{\mu}\left(${p}\right) + \left|\left|\vec{q}\right|\right|^2}
- `,
- evaluate: (data, target) => Math.sqrt(data.inertia - 2 * vectorDot(data.mu.vector, target.vector) + target.sqMag),
- },
- bigTheta: { // 1 - arith mean of cosine similarity
- option: "Cosine Difference (Θ)",
- displayName: String.raw`\Theta`,
- displayBody: p => String.raw`
- 1 - \hat{q}\cdot\vec{\nu}\left(${p}\right)
- `,
- evaluate: (data, target) => 1 - vectorDot(data.nu, target.unit),
- },
- theta: { // angle of mean
- option: "Angular Difference (θ)",
- displayName: String.raw`\theta`,
- displayBody: p => String.raw`
- \cos^{-1}\left( \hat{q}\cdot\hat{\mu}\left(${p}\right) \right)
- `,
- evaluate: (data, target) => rad2deg * Math.acos(vectorDot(data.mu.unit, target.unit)),
- },
- phi: { // hue angle
- option: "Hue Azimuth (ϕ)",
- displayName: String.raw`\phi`,
- displayBody: (p, space) => String.raw`
- \angle \left(\text{oproj}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{q}}, \text{oproj}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{\mu}\left(${p}\right)} \right)
- `,
- evaluate: (data, target) => {
- const raw = Math.abs(data.mu.hue - target.hue);
- return Math.min(raw, 360 - raw);
- },
- },
- delta: { // euclidean
- option: "Euclidean (δ)",
- displayName: String.raw`\delta`,
- displayBody: p => String.raw`
- \left|\left| \vec{q} - \vec{\mu}\left(${p}\right) \right|\right|
- `,
- evaluate: (data, target) => vectorMag(data.mu.vector.map((x, i) => x - target.vector[i])),
- },
- manhattan: { // manhattan distance
- option: "Manhattan (M)",
- displayName: "M",
- displayBody: p => String.raw`
- \sum_{i} \left| \vec{\mu}\left(${p}\right)_i - \vec{q}_i \right|
- `,
- evaluate: (data, target) => data.mu.vector.map((x, i) => Math.abs(x - target.vector[i])).reduce((x, y) => x + y),
- },
- ch: { // chebyshev
- option: "Chebyshev (Ч)",
- displayName: "Ч",
- displayBody: p => String.raw`
- \max_{i} \left| \vec{\mu}\left(${p}\right)_i - \vec{q}_i \right|
- `,
- evaluate: (data, target) => Math.max(...data.mu.vector.map((x, i) => Math.abs(x - target.vector[i]))),
- },
- lightnessDiff: {
- option: "Lightness (ℓ)",
- displayName: String.raw`\ell`,
- displayBody: (p, space) => String.raw`
- \left| ${space === "jab" ? "\\frac{1}{100}" : ""}\text{comp}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{q}} - ${space === "jab" ? "\\frac{1}{100}" : ""}\text{comp}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{\mu}\left(${p}\right)} \right|
- `,
- evaluate: (data, target) => Math.abs(data.mu.lightness - target.lightness),
- },
- inertia: {
- option: "Inertia (I)",
- displayName: "I",
- displayBody: p => String.raw`
- \frac{1}{\left|${p}\right|} \sum_{p\in ${p}}{\left|\left|\vec{p}\right|\right|^2}
- `,
- evaluate: data => data.inertia,
- },
- variance: {
- option: "Variance (V)",
- displayName: "V",
- displayBody: p => String.raw`
- I\left(${p}\right) - \left|\left|\vec{\mu}\left(${p}\right)\right|\right|^2
- `,
- evaluate: data => data.inertia - data.mu.sqMag
- },
- muNuAngle: {
- option: "Mu-Nu Angle (Φ)",
- displayName: "\\Phi",
- displayBody: p => String.raw`\angle \left( \vec{\mu}\left(${p}\right), \vec{\nu}\left(${p}\right) \right)`,
- evaluate: data => data.muNuAngle,
- },
- size: {
- option: "Size (N)",
- displayName: "N",
- displayBody: p => String.raw`\left|${p}\right|`,
- evaluate: data => data.size,
- },
- lightness: {
- option: "Mean Lightness (L)",
- displayName: "L",
- displayBody: (p, space) => String.raw`
- ${space === "jab" ? "\\frac{1}{100}" : ""}\text{comp}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{\mu}\left(${p}\right)}
- `,
- evaluate: data => data.mu.lightness,
- },
- chroma: {
- option: "Mean Chroma (C)",
- displayName: "C",
- displayBody: p => String.raw`\text{chroma}\left(\vec{\mu}\left(${p}\right)\right)`,
- evaluate: data => data.mu.chroma,
- },
- importance: {
- option: "Visual Importance (β)",
- displayName: String.raw`\beta`,
- displayBody: p => String.raw`
- \begin{aligned}
- &C\left(${p}\right) + L\left(${p}\right) + \frac{\left|${p}\right|}{\left|P\right|}\\
- + &\tanh{\left(100\left(C\left(${p}\right) - 0.25\right)\right)} \\
- + &\tanh{\left(100\left(C\left(${p}\right) - 0.4\right)\right)} \\
- + &\tanh{\left(100\left(L\left(${p}\right) - 0.5\right)\right)} \\
- + &\tanh{\left(100\left(\frac{\left|${p}\right|}{\left|P\right|} - 0.05\right)\right)} \\
- + &\tanh{\left(100\left(\frac{\left|${p}\right|}{\left|P\right|} - 0.10\right)\right)} \\
- + &\tanh{\left(100\left(\frac{\left|${p}\right|}{\left|P\right|} - 0.15\right)\right)} \\
- + &\tanh{\left(100\left(\frac{\left|${p}\right|}{\left|P\right|} - 0.25\right)\right)} \\
- + &\tanh{\left(100\left(\frac{\left|${p}\right|}{\left|P\right|} - 0.80\right)\right)}
- \end{aligned}
- `,
- evaluate: data => data.importance,
- },
- };
- const applyMetrics = (data, target) => {
- const scores = Object.fromEntries(
- Object.entries(metrics)
- .map(([name, metric]) => [name, metric.evaluate(data, target)])
- );
- scores.alpha = scores.sigma * Math.pow(scores.bigTheta, target.chroma + target.lightness);
- return scores;
- };
|