diff --git a/Surge.xcodeproj/project.pbxproj b/Surge.xcodeproj/project.pbxproj index 9e56bd7..b67a4e0 100644 --- a/Surge.xcodeproj/project.pbxproj +++ b/Surge.xcodeproj/project.pbxproj @@ -91,6 +91,9 @@ CAAF500C233A7B6700CC0AA7 /* Surge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 614AD31F1FC0AD99002BFE1C /* Surge.framework */; }; CAAF5015233A7D4100CC0AA7 /* ArithmeticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAF5014233A7C7900CC0AA7 /* ArithmeticTests.swift */; }; CAAF501A233A9E6300CC0AA7 /* SurgeBenchmarkTests+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAF5019233A9E6300CC0AA7 /* SurgeBenchmarkTests+Extensions.swift */; }; + CAD8E5CB2343FD38001B172A /* StatisticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */; }; + CAD8E5CC2343FD38001B172A /* StatisticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */; }; + CAD8E5CD2343FD38001B172A /* StatisticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */; }; CAEC79BF2319274F00516E10 /* OperatorPrecedences.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAEC79B72319244D00516E10 /* OperatorPrecedences.swift */; }; CAEC79C02319275000516E10 /* OperatorPrecedences.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAEC79B72319244D00516E10 /* OperatorPrecedences.swift */; }; CAEC79C12319275000516E10 /* OperatorPrecedences.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAEC79B72319244D00516E10 /* OperatorPrecedences.swift */; }; @@ -188,6 +191,7 @@ CAAF500B233A7B6700CC0AA7 /* Info-BenchmarkTests.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-BenchmarkTests.plist"; sourceTree = ""; }; CAAF5014233A7C7900CC0AA7 /* ArithmeticTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArithmeticTests.swift; sourceTree = ""; }; CAAF5019233A9E6300CC0AA7 /* SurgeBenchmarkTests+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SurgeBenchmarkTests+Extensions.swift"; sourceTree = ""; }; + CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsTests.swift; sourceTree = ""; }; CAEC79B72319244D00516E10 /* OperatorPrecedences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorPrecedences.swift; sourceTree = ""; }; CAEC79C323192FE300516E10 /* Scalar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scalar.swift; sourceTree = ""; }; CAEC79D12319343100516E10 /* Logarithm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logarithm.swift; sourceTree = ""; }; @@ -300,6 +304,7 @@ 61A0AD741F70D22600B99FFB /* TrigonometricTests.swift */, CAFE5DAD22F9ED4900A34887 /* VectorTests.swift */, CAAF4FCF2338F09700CC0AA7 /* ScalarTests.swift */, + CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */, CAFE5DA422F9EC1D00A34887 /* XCTAssert+Surge.swift */, CA945C2C233ABC0D00D95127 /* SurgeTests+Extensions.swift */, ); @@ -858,6 +863,7 @@ CAAF5001233A701A00CC0AA7 /* LogarithmTests.swift in Sources */, 614AD3481FC0AF77002BFE1C /* MatrixTests.swift in Sources */, CAAF4FFD2339651700CC0AA7 /* ScalarTests.swift in Sources */, + CAD8E5CC2343FD38001B172A /* StatisticsTests.swift in Sources */, 614AD3441FC0AF77002BFE1C /* AuxiliaryTests.swift in Sources */, 614AD3451FC0AF77002BFE1C /* ConvolutionTests.swift in Sources */, CAFE5DAF22F9ED4900A34887 /* VectorTests.swift in Sources */, @@ -898,6 +904,7 @@ CAAF5002233A701A00CC0AA7 /* LogarithmTests.swift in Sources */, 614AD3791FC0B0D2002BFE1C /* MatrixTests.swift in Sources */, CAAF4FFE2339651800CC0AA7 /* ScalarTests.swift in Sources */, + CAD8E5CD2343FD38001B172A /* StatisticsTests.swift in Sources */, 614AD3751FC0B0D2002BFE1C /* AuxiliaryTests.swift in Sources */, 614AD3761FC0B0D2002BFE1C /* ConvolutionTests.swift in Sources */, CAFE5DB022F9ED4900A34887 /* VectorTests.swift in Sources */, @@ -950,6 +957,7 @@ CAAF5000233A701A00CC0AA7 /* LogarithmTests.swift in Sources */, 61A0AD7B1F70D22600B99FFB /* MatrixTests.swift in Sources */, CAAF4FFC2339651600CC0AA7 /* ScalarTests.swift in Sources */, + CAD8E5CB2343FD38001B172A /* StatisticsTests.swift in Sources */, 61A0AD771F70D22600B99FFB /* AuxiliaryTests.swift in Sources */, 61A0AD781F70D22600B99FFB /* ConvolutionTests.swift in Sources */, CAFE5DAE22F9ED4900A34887 /* VectorTests.swift in Sources */, diff --git a/Tests/SurgeTests/ArithmeticTests.swift b/Tests/SurgeTests/ArithmeticTests.swift index 8d2b914..9fd2a57 100644 --- a/Tests/SurgeTests/ArithmeticTests.swift +++ b/Tests/SurgeTests/ArithmeticTests.swift @@ -404,32 +404,6 @@ class ArithmeticTests: XCTestCase { XCTAssertEqual(actual, expected, accuracy: 1e-8) } - // MARK: - Summation - - func test_sum_array_float() { - typealias Scalar = Float - - let lhs: [Scalar] = .monotonicNormalized() - - let actual: Scalar = Surge.sum(lhs) - - let expected: Scalar = lhs.reduce(0, +) - - XCTAssertEqual(actual, expected, accuracy: 1e-1) - } - - func test_sum_array_double() { - typealias Scalar = Double - - let lhs: [Scalar] = .monotonicNormalized() - - let actual: Scalar = Surge.sum(lhs) - - let expected: Scalar = lhs.reduce(0, +) - - XCTAssertEqual(actual, expected, accuracy: 1e-8) - } - // MARK: - Distance func test_dist_array_array_float() { diff --git a/Tests/SurgeTests/StatisticsTests.swift b/Tests/SurgeTests/StatisticsTests.swift new file mode 100644 index 0000000..2a717e0 --- /dev/null +++ b/Tests/SurgeTests/StatisticsTests.swift @@ -0,0 +1,366 @@ +// Copyright © 2014-2019 the Surge contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import XCTest + +@testable import Surge + +// swiftlint:disable nesting + +class StatisticsTests: XCTestCase { + // MARK: - Sum + + func test_sum_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.sum(lhs) + + let expected: Scalar = lhs.reduce(0) { $0 + $1 } + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_sum_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.sum(lhs) + + let expected: Scalar = lhs.reduce(0) { $0 + $1 } + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + + // MARK: - Sum of Absolute Values + + func test_asum_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.asum(lhs) + + let expected: Scalar = lhs.reduce(0) { $0 + abs($1) } + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_asum_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.asum(lhs) + + let expected: Scalar = lhs.reduce(0) { $0 + abs($1) } + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + + // MARK: - Sum of Absolute Values + + func test_sumsq_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.sumsq(lhs) + + let expected: Scalar = lhs.reduce(0) { $0 + ($1 * $1) } + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_sumsq_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.sumsq(lhs) + + let expected: Scalar = lhs.reduce(0) { $0 + ($1 * $1) } + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + + // MARK: - Maximum + + func test_max_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.max(lhs) + + let expected: Scalar = lhs.max()! + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_max_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.max(lhs) + + let expected: Scalar = lhs.max()! + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + + // MARK: - Minimum + + func test_min_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.min(lhs) + + let expected: Scalar = lhs.min()! + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_min_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.min(lhs) + + let expected: Scalar = lhs.min()! + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + + // MARK: - Mean + + func test_mean_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.mean(lhs) + + let expected: Scalar = { + let sum = lhs.reduce(0) { $0 + $1 } + return sum / Scalar(lhs.count) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_mean_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.mean(lhs) + + let expected: Scalar = { + let sum = lhs.reduce(0) { $0 + $1 } + return sum / Scalar(lhs.count) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + + // MARK: - Mean of Magnitudes + + func test_meamg_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.meamg(lhs) + + let expected: Scalar = { + let sum = lhs.reduce(0) { $0 + abs($1) } + return sum / Scalar(lhs.count) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_meamg_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.meamg(lhs) + + let expected: Scalar = { + let sum = lhs.reduce(0) { $0 + abs($1) } + return sum / Scalar(lhs.count) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + + // MARK: - Mean of Squares + + func test_measq_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.measq(lhs) + + let expected: Scalar = { + let sum = lhs.reduce(0) { $0 + ($1 * $1) } + return sum / Scalar(lhs.count) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_measq_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.measq(lhs) + + let expected: Scalar = { + let sum = lhs.reduce(0) { $0 + ($1 * $1) } + return sum / Scalar(lhs.count) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + + // MARK: - Root Mean of Squares + + func test_rmsq_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.rmsq(lhs) + + let expected: Scalar = { + let sum = lhs.reduce(0) { $0 + ($1 * $1) } + let mean = sum / Scalar(lhs.count) + return sqrt(mean) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_rmsq_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.rmsq(lhs) + + let expected: Scalar = { + let sum = lhs.reduce(0) { $0 + ($1 * $1) } + let mean = sum / Scalar(lhs.count) + return sqrt(mean) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + + // MARK: - Variance + + func test_variance_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.variance(lhs) + + let expected: Scalar = { + let mean = lhs.reduce(0) { $0 + $1 } / Scalar(lhs.count) + let diff = lhs.map { $0 - mean } + let diffSq = diff.map { $0 * $0 } + let sumDiffSq = diffSq.reduce(0.0) { $0 + $1 } + return sumDiffSq / Scalar(lhs.count - 1) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + func test_variance_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.variance(lhs) + + let expected: Scalar = { + let mean = lhs.reduce(0) { $0 + $1 } / Scalar(lhs.count) + let diff = lhs.map { $0 - mean } + let diffSq = diff.map { $0 * $0 } + let sumDiffSq = diffSq.reduce(0.0) { $0 + $1 } + return sumDiffSq / Scalar(lhs.count - 1) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-4) + } + + // MARK: - Standard Deviation + + func test_std_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.std(lhs) + + let expected: Scalar = { + let mean = lhs.reduce(0) { $0 + $1 } / Scalar(lhs.count) + let diff = lhs.map { $0 - mean } + let diffSq = diff.map { $0 * $0 } + let sumDiffSq = diffSq.reduce(0.0) { $0 + $1 } + let variance = sumDiffSq / Scalar(lhs.count - 1) + return sqrt(variance) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-3) + } + + func test_std_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = .monotonicNormalized() + + let actual: Scalar = Surge.std(lhs) + + let expected: Scalar = { + let mean = lhs.reduce(0) { $0 + $1 } / Scalar(lhs.count) + let diff = lhs.map { $0 - mean } + let diffSq = diff.map { $0 * $0 } + let sumDiffSq = diffSq.reduce(0.0) { $0 + $1 } + let variance = sumDiffSq / Scalar(lhs.count - 1) + return sqrt(variance) + }() + + XCTAssertEqual(actual, expected, accuracy: 1e-3) + } +}