packages feed

zwirn-0.2.2.0: src/zwirn-core/Zwirn/Core/Query.hs

{-# LANGUAGE BangPatterns #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-# OPTIONS_GHC -Wno-type-defaults #-}

module Zwirn.Core.Query where

{-
    Query.hs - querying signals for breakpoints
    (i.e. the zeroes of the fractional part of the inner time of a signal)
    Copyright (C) 2025, Martin Gius

    This library is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
-}

import Data.List (uncons)
import Zwirn.Core.Time
import Zwirn.Core.Tree hiding (concat)
import Zwirn.Core.Types

type Breakpoint st i a = (Time, Value i a, st)

instance (Show a, Num st, ToList k) => Show (ZwirnT k st i a) where
  show = show . findAllValuesWithTime (Time 0 1, Time 1 1) 0

findAllValuesWithTime :: (ToList k) => (Time, Time) -> st -> ZwirnT k st i a -> [(Time, a)]
findAllValuesWithTime = findAllValuesWithTimePrec 0.005

findAllValuesWithTimeState :: (ToList k) => (Time, Time) -> st -> ZwirnT k st i a -> ([(Time, a)], st)
findAllValuesWithTimeState = findAllValuesWithTimeStatePrec 0.005

findAllValuesWithTimePrec :: (ToList k) => Time -> (Time, Time) -> st -> ZwirnT k st i a -> [(Time, a)]
findAllValuesWithTimePrec prec (start, end) st z = map (\(t, v, _) -> (t, value v)) xs
  where
    (xs, _) = findAllBreakpoints prec start end st z

findAllValuesWithTimeStatePrec :: (ToList k) => Time -> (Time, Time) -> st -> ZwirnT k st i a -> ([(Time, a)], st)
findAllValuesWithTimeStatePrec prec (start, end) st z = (map (\(t, v, _) -> (t, value v)) xs, st')
  where
    (xs, st') = findAllBreakpoints prec start end st z

checkBreakpoint :: (ToList k) => Time -> Time -> st -> ZwirnT k st i a -> ([Breakpoint st i a], st)
checkBreakpoint !prec !now st z = (concatMap func vs, newst)
  where
    vs = toList $ unzwirn z now st
    func (v, _) = [(now, v, st) | breakpointCondition prec (time v)]
    newst = case uncons vs of
      (Just ((_, st'), _)) -> st'
      Nothing -> st

breakpointCondition :: Time -> Time -> Bool
breakpointCondition prec (Time !t !diff)
  | diff > 0 = frac t / diff < tTime prec
  | diff == 0 = False
  | otherwise = frac (abs t) / abs diff < tTime prec

findAllBreakpoints :: (ToList k) => Time -> Time -> Time -> st -> ZwirnT k st i a -> ([Breakpoint st i a], st)
findAllBreakpoints prec !now end initialSt z = go [] now initialSt
  where
    !limit = end - prec
    go acc !t !st
      | t > limit = (reverse acc, st)
      | otherwise = case checkBreakpoint prec t st z of
          ([], st') -> go acc (t + prec) st'
          (bps, newst) -> go (reverse bps ++ acc) (t + prec) newst