Pith - kiln
kiln/app/src/main/java/com/vgmlr/kiln/KilnMoodInfluence.kt [2.0 kb]
Modified: 20:13:54 158 026 (24 Aug 026)
5 Days Ago
package com.vgmlr.kiln

import java.time.LocalDate
import java.time.temporal.ChronoUnit
import kotlin.math.abs

object KilnMoodInfluence {
    private const val MIN_MOOD_DAYS = 20
    private const val RAMP_DAYS = 28
    private const val BUCKET_DEG = 120f / 7f
    private const val SMOOTH = 2L

    fun weight(records: List<KilnDayRecord>, buttons: KilnButtonSet): Float {
        val n = records.count { it.mood != null || buttons.hasSymptom(it) }
        return ((n - MIN_MOOD_DAYS).toFloat() / RAMP_DAYS).coerceIn(0f, 1f)
    }

    private val DRAG = floatArrayOf(2f, 1f, 0f, 1f, 2f)
    private fun drag(mood: Int): Float = DRAG.getOrElse(mood) { 0f }

    private const val SYMPTOM_DRAG = 0.8f
    
    fun hueShift(
        records: List<KilnDayRecord>,
        buttons: KilnButtonSet,
        starts: List<LocalDate>,
        cycle: Int,
        date: LocalDate
    ): Float {
        val w = weight(records, buttons)
        if (w == 0f || starts.isEmpty()) return 0f
        val phase = phaseOf(date, starts, cycle) ?: return 0f

        var sum = 0f
        var n = 0
        for (r in records) {
            val p = phaseOf(LocalDate.ofEpochDay(r.epochDay), starts, cycle) ?: continue
            if (circularDist(p, phase, cycle) > SMOOTH) continue
            r.mood?.let { sum += drag(it); n++ }
            val s = buttons.symptomCount(r)
            if (s > 0) {
                sum += SYMPTOM_DRAG * s
                n += s
            }
        }
        if (n == 0) return 0f

        val avg = sum / n
        val confidence = n / (n + 3f)
        return -avg * BUCKET_DEG * w * confidence
    }

    private fun phaseOf(date: LocalDate, starts: List<LocalDate>, cycle: Int): Long? {
        val last = starts.lastOrNull { !it.isAfter(date) } ?: return null
        return Math.floorMod(ChronoUnit.DAYS.between(last, date), cycle.toLong())
    }

    private fun circularDist(a: Long, b: Long, cycle: Int): Long {
        val d = abs(a - b)
        return minOf(d, cycle - d)
    }
}
Updates
Stave - Android 158.026
Kerf - Android 157.026
Kiln - Android 157.026
Wedge - Android 156.026
Whittle - Linux 155.026

Menu
Calendar
Project Tin (024/029)
Miter
RSS Feed
User Avatar
@vgmlr
=SUM(parts)
0.00291
260,191 (+605)