metrics.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. const metrics = {
  2. sigma: { // RMS
  3. option: "RMS Deviation (σ)",
  4. displayName: String.raw`\sigma`,
  5. displayBody: p => String.raw`
  6. \sqrt{I\left(${p}\right) - 2\vec{q}\cdot\vec{\mu}\left(${p}\right) + \left|\left|\vec{q}\right|\right|^2}
  7. `,
  8. evaluate: (data, target) => Math.sqrt(data.inertia - 2 * vectorDot(data.mu.vector, target.vector) + target.sqMag),
  9. },
  10. bigTheta: { // 1 - arith mean of cosine similarity
  11. option: "Cosine Difference (Θ)",
  12. displayName: String.raw`\Theta`,
  13. displayBody: p => String.raw`
  14. 1 - \hat{q}\cdot\vec{\nu}\left(${p}\right)
  15. `,
  16. evaluate: (data, target) => 1 - vectorDot(data.nu, target.unit),
  17. },
  18. alpha: { // combine sigma and bigTheta
  19. option: "Geometric Difference (α)",
  20. displayName: String.raw`\alpha`,
  21. displayBody: p => String.raw`
  22. \sqrt{\sigma\left(${p}\right)\Theta\left(${p}\right)}
  23. `,
  24. evaluate: () => 0, // calculated below
  25. },
  26. theta: { // angle of mean
  27. option: "Angular Difference (θ)",
  28. displayName: String.raw`\theta`,
  29. displayBody: p => String.raw`
  30. \cos^{-1}\left( \hat{q}\cdot\hat{\mu}\left(${p}\right) \right)
  31. `,
  32. evaluate: (data, target) => rad2deg * Math.acos(vectorDot(data.mu.unit, target.unit)),
  33. },
  34. phi: { // hue angle
  35. option: "Hue Azimuth (ϕ)",
  36. displayName: String.raw`\phi`,
  37. displayBody: (p, space) => String.raw`
  38. \angle \left(\text{oproj}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{q}}, \text{oproj}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{\mu}\left(${p}\right)} \right)
  39. `,
  40. evaluate: (data, target) => {
  41. const raw = Math.abs(data.mu.hue - target.hue);
  42. return Math.min(raw, 360 - raw);
  43. },
  44. },
  45. delta: { // euclidean
  46. option: "Euclidean (δ)",
  47. displayName: String.raw`\delta`,
  48. displayBody: p => String.raw`
  49. \left|\left| \vec{q} - \vec{\mu}\left(${p}\right) \right|\right|
  50. `,
  51. evaluate: (data, target) => vectorMag(data.mu.vector.map((x, i) => x - target.vector[i])),
  52. },
  53. manhattan: { // manhattan distance
  54. option: "Manhattan (M)",
  55. displayName: "M",
  56. displayBody: p => String.raw`
  57. \sum_{i} \left| \vec{\mu}\left(${p}\right)_i - \vec{q}_i \right|
  58. `,
  59. evaluate: (data, target) => data.mu.vector.map((x, i) => Math.abs(x - target.vector[i])).reduce((x, y) => x + y),
  60. },
  61. ch: { // chebyshev
  62. option: "Chebyshev (Ч)",
  63. displayName: "Ч",
  64. displayBody: p => String.raw`
  65. \max_{i} \left| \vec{\mu}\left(${p}\right)_i - \vec{q}_i \right|
  66. `,
  67. evaluate: (data, target) => Math.max(...data.mu.vector.map((x, i) => Math.abs(x - target.vector[i]))),
  68. },
  69. lightnessDiff: {
  70. option: "Lightness (ℓ)",
  71. displayName: String.raw`\ell`,
  72. displayBody: (p, space) => String.raw`
  73. \left| \text{comp}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{q}} - \text{comp}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{\mu}\left(${p}\right)} \right|
  74. `,
  75. evaluate: (data, target) => Math.abs(data.mu.lightness - target.lightness),
  76. },
  77. inertia: {
  78. option: "Inertia (I)",
  79. displayName: "I",
  80. displayBody: p => String.raw`
  81. \frac{1}{\left|${p}\right|} \sum_{p\in ${p}}{\left|\left|\vec{p}\right|\right|^2}
  82. `,
  83. evaluate: data => data.inertia,
  84. },
  85. lightness: {
  86. option: "Mean Lightness (ℒ)",
  87. displayName: String.raw`\mathcal{L}`,
  88. displayBody: (p, space) => String.raw`
  89. \text{comp}_{\vec{${space === "jab" ? "J" : "L"}}}{\vec{\mu}\left(${p}\right)}
  90. `,
  91. evaluate: data => data.mu.lightness,
  92. },
  93. muNuAngle: {
  94. option: "Mu-Nu Angle (V)",
  95. displayName: "V",
  96. displayBody: p => String.raw`\angle \left( \vec{\mu}\left(${p}\right), \vec{\nu}\left(${p}\right) \right)`,
  97. evaluate: data => data.muNuAngle,
  98. },
  99. size: {
  100. option: "Size (N)",
  101. displayName: "N",
  102. displayBody: p => String.raw`\left|${p}\right|`,
  103. evaluate: data => data.size,
  104. }
  105. };
  106. const applyMetrics = (data, target) => {
  107. const scores = Object.fromEntries(
  108. Object.entries(metrics)
  109. .map(([name, metric]) => [name, metric.evaluate(data, target)])
  110. );
  111. // rearranges to geometric mean of sigma and bigTheta
  112. scores.alpha = Math.sqrt(scores.sigma * scores.bigTheta);
  113. return scores;
  114. };