From 823aa3c7ca9801bb0b54bde59950733f0de52c6f Mon Sep 17 00:00:00 2001 From: Ivan Perez Date: Thu, 8 Aug 2024 09:54:21 +0000 Subject: [PATCH 1/8] yampa: Implement integral using trapezoid rule. Refs #263. The current implementation of integral has a tendency to diverge. This commonly manifests in games as bouncing elements that bounce more and more over time, or springs that bounce harder. In the general case, the energy of the simulated system increases over time. This commit introduces a new integral function that uses the trapezoid rule. The new integral can be more accurate and does not increase over time in the same way that the rectangle rule does. Co-authored-by: Dominic Steinitz Co-authored-by: Miguel Negrao --- yampa/src/FRP/Yampa.hs | 1 + yampa/src/FRP/Yampa/Integration.hs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/yampa/src/FRP/Yampa.hs b/yampa/src/FRP/Yampa.hs index 785eb711..c3fb6eac 100644 --- a/yampa/src/FRP/Yampa.hs +++ b/yampa/src/FRP/Yampa.hs @@ -280,6 +280,7 @@ module FRP.Yampa -- ** Integration and differentiation , integral , imIntegral + , trapezoidIntegral , impulseIntegral , count , derivative diff --git a/yampa/src/FRP/Yampa/Integration.hs b/yampa/src/FRP/Yampa/Integration.hs index 99413bda..e5fe2bdf 100644 --- a/yampa/src/FRP/Yampa/Integration.hs +++ b/yampa/src/FRP/Yampa/Integration.hs @@ -32,6 +32,7 @@ module FRP.Yampa.Integration -- * Integration integral , imIntegral + , trapezoidIntegral , impulseIntegral , count @@ -71,6 +72,12 @@ integral = SF {sfTF = tf0} imIntegral :: (Fractional s, VectorSpace a s) => a -> SF a a imIntegral = ((\_ a' dt v -> v ^+^ realToFrac dt *^ a') `iterFrom`) +-- | Trapezoid integral (using the average between the value at the last time +-- and the value at the current time). +trapezoidIntegral :: (Fractional s, VectorSpace a s) => SF a a +trapezoidIntegral = + iterFrom (\a a' dt v -> v ^+^ (realToFrac dt / 2) *^ (a ^+^ a')) zeroVector + -- | Integrate the first input signal and add the /discrete/ accumulation (sum) -- of the second, discrete, input signal. impulseIntegral :: (Fractional k, VectorSpace a k) => SF (a, Event a) a From 1e60c30de9677f8cdd562cc60d0ded709ede24eb Mon Sep 17 00:00:00 2001 From: Ivan Perez Date: Thu, 8 Aug 2024 10:38:04 +0000 Subject: [PATCH 2/8] yampa-test: Add test for trapezoidIntegral. Refs #263. This commit adds a test for the new trapezoid integral. The test is based on the existing integral. --- .../tests/Test/FRP/Yampa/Integration.hs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/yampa-test/tests/Test/FRP/Yampa/Integration.hs b/yampa-test/tests/Test/FRP/Yampa/Integration.hs index 0220e70f..ad63cb59 100644 --- a/yampa-test/tests/Test/FRP/Yampa/Integration.hs +++ b/yampa-test/tests/Test/FRP/Yampa/Integration.hs @@ -27,6 +27,8 @@ tests = testGroup "Regression tests for FRP.Yampa.Integration" , testProperty "imIntegral (0, qc)" testImIntegral0 , testProperty "imIntegral (1, qc)" testImIntegral1 , testProperty "imIntegral (2, qc)" testImIntegral2 + , testProperty "trapezoidIntegral (0, qc)" testTrapezoidIntegral0 + , testProperty "trapezoidIntegral (1, qc)" testTrapezoidIntegral1 , testProperty "impulseIntegral (0, fixed)" (property $ utils_t7 ~= utils_t7r) , testProperty "count (0, fixed)" (property $ utils_t4 ~= utils_t4r) , testProperty "count (1, fixed)" (property $ utils_t5 ~= utils_t5r) @@ -149,6 +151,40 @@ testImIntegral2 = close (x,y) = abs (x-y) < 0.05 +testTrapezoidIntegral0 :: Property +testTrapezoidIntegral0 = + forAll myStream $ evalT $ + Next $ Always $ prop ((sf &&& sfByHand), const close) + + where + myStream :: Gen (SignalSampleStream Double) + myStream = uniDistStream + + sf :: SF Double Double + sf = trapezoidIntegral >>> derivative + + sfByHand :: SF Double Double + sfByHand = (identity &&& iPre 0) >>^ (\(x, y) -> (x + y) / 2) + + close (x,y) = abs (x-y) < 0.05 + +testTrapezoidIntegral1 :: Property +testTrapezoidIntegral1 = + forAll myStream $ evalT $ + Next $ Always $ prop ((sf &&& sfByHand), const close) + + where + myStream :: Gen (SignalSampleStream Double) + myStream = uniDistStream + + sf :: SF Double Double + sf = arr (*2) >>> trapezoidIntegral + + sfByHand :: SF Double Double + sfByHand = trapezoidIntegral >>> arr (*2) + + close (x,y) = abs (x-y) < 0.05 + utils_t7 :: [Double] utils_t7 = take 50 $ embed impulseIntegral (deltaEncode 0.1 (zip (repeat 1.0) evSeq)) From 592bd446c4ac78fc19a79c184ed3e711cbc7be4e Mon Sep 17 00:00:00 2001 From: Ivan Perez Date: Wed, 7 Aug 2024 09:41:33 +0000 Subject: [PATCH 3/8] yampa: Document changes in CHANGELOG. Refs #263. --- yampa/CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yampa/CHANGELOG b/yampa/CHANGELOG index 60852a0e..6546ed5b 100644 --- a/yampa/CHANGELOG +++ b/yampa/CHANGELOG @@ -1,3 +1,6 @@ +2024-08-07 Ivan Perez + * Implement integral using trapezoid rule (#263). + 2024-06-08 Ivan Perez * Version bump (0.14.9) (#299). * Document FRP.Yampa.Random.streamToSF (#296). From 8a53e37ce26251fdd407698f454fd16084d1efff Mon Sep 17 00:00:00 2001 From: Ivan Perez Date: Thu, 8 Aug 2024 10:45:02 +0000 Subject: [PATCH 4/8] yampa-test: Document changes in CHANGELOG. Refs #263. --- yampa-test/CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yampa-test/CHANGELOG b/yampa-test/CHANGELOG index 800cb239..98bf63f1 100644 --- a/yampa-test/CHANGELOG +++ b/yampa-test/CHANGELOG @@ -1,3 +1,6 @@ +2024-08-07 Ivan Perez + * Add test for trapezoidIntegral (#263). + 2024-06-08 Ivan Perez * Version bump (0.14.9) (#299). From a7d1d3343807b4ffbaa4ec3d6de2e9d8a05d77e6 Mon Sep 17 00:00:00 2001 From: Ivan Perez Date: Thu, 8 Aug 2024 11:00:52 +0000 Subject: [PATCH 5/8] yampa: Version bump (0.14.10). Refs #302. --- yampa/Yampa.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yampa/Yampa.cabal b/yampa/Yampa.cabal index 9d7c0ef6..dc533dca 100644 --- a/yampa/Yampa.cabal +++ b/yampa/Yampa.cabal @@ -30,7 +30,7 @@ cabal-version: >= 1.10 build-type: Simple name: Yampa -version: 0.14.9 +version: 0.14.10 author: Henrik Nilsson, Antony Courtney maintainer: Ivan Perez (ivan.perez@keera.co.uk) homepage: https://github.com/ivanperez-keera/Yampa/ From 4a8f1e0811af3600cc543bd056b1a7ddc5271352 Mon Sep 17 00:00:00 2001 From: Ivan Perez Date: Thu, 8 Aug 2024 11:01:10 +0000 Subject: [PATCH 6/8] yampa-test: Version bump (0.14.10). Refs #302. --- yampa-test/yampa-test.cabal | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yampa-test/yampa-test.cabal b/yampa-test/yampa-test.cabal index 4a69d2eb..42273471 100644 --- a/yampa-test/yampa-test.cabal +++ b/yampa-test/yampa-test.cabal @@ -31,7 +31,7 @@ cabal-version: >= 1.10 build-type: Simple name: yampa-test -version: 0.14.9 +version: 0.14.10 author: Ivan Perez maintainer: ivan.perez@keera.co.uk homepage: http://github.com/ivanperez-keera/Yampa @@ -84,7 +84,7 @@ library base >= 4 && < 5 , normaldistribution >= 1.1.0.1 && < 1.2 , QuickCheck >= 2.12 && < 2.15 - , Yampa >= 0.14.9 && < 0.15 + , Yampa >= 0.14.10 && < 0.15 default-language: Haskell2010 From 778d9adef40464cdfddea2310332d7d7140f7eab Mon Sep 17 00:00:00 2001 From: Ivan Perez Date: Thu, 8 Aug 2024 11:01:37 +0000 Subject: [PATCH 7/8] yampa: Document changes in CHANGELOG. Refs #302. --- yampa/CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/yampa/CHANGELOG b/yampa/CHANGELOG index 6546ed5b..ef629cf5 100644 --- a/yampa/CHANGELOG +++ b/yampa/CHANGELOG @@ -1,4 +1,5 @@ 2024-08-07 Ivan Perez + * Version bump (0.14.10) (#302). * Implement integral using trapezoid rule (#263). 2024-06-08 Ivan Perez From c322c58160e4099f1b0f2c6b9603519cc7d4edf2 Mon Sep 17 00:00:00 2001 From: Ivan Perez Date: Thu, 8 Aug 2024 11:01:53 +0000 Subject: [PATCH 8/8] yampa-test: Document changes in CHANGELOG. Refs #302. --- yampa-test/CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/yampa-test/CHANGELOG b/yampa-test/CHANGELOG index 98bf63f1..283c9ba7 100644 --- a/yampa-test/CHANGELOG +++ b/yampa-test/CHANGELOG @@ -1,4 +1,5 @@ 2024-08-07 Ivan Perez + * Version bump (0.14.10) (#302). * Add test for trapezoidIntegral (#263). 2024-06-08 Ivan Perez