├── .azure
└── pipelines
│ ├── ci-benchmarks.yml
│ ├── ci-demos.yml
│ ├── ci-docs.yml
│ ├── ci.yml
│ └── jobs
│ ├── benchmarks.yml
│ ├── build_and_test.yml
│ ├── build_docs.yml
│ ├── coverage.yml
│ ├── demos.yml
│ ├── deploy_docs.yml
│ ├── deploy_nuget.yml
│ └── steps
│ └── dotnet-install.yml
├── .editorconfig
├── .gitattributes
├── .github
├── CODEOWNERS
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ └── bug_report.md
└── pull_request_template.md
├── .gitignore
├── Directory.Build.props
├── Directory.Build.targets
├── LICENSE
├── README.md
├── api-doc
├── .gitignore
├── api
│ ├── .gitignore
│ └── index.md
├── articles
│ ├── DeadBand.md
│ ├── SwingingDoor.md
│ ├── images
│ │ ├── DeadBand_01.jpg
│ │ ├── DeadBand_02.png
│ │ ├── dead-band_error.png
│ │ ├── dead-band_maxDelta.png
│ │ ├── dead-band_trend.png
│ │ ├── demo_01.png
│ │ ├── demo_02.png
│ │ ├── demo_03.png
│ │ ├── swinging-door_01.png
│ │ ├── swinging-door_02.png
│ │ ├── swinging-door_error.png
│ │ ├── swinging-door_maxDelta.png
│ │ └── swinging-door_trend.png
│ └── toc.yml
├── docfx.json
├── filterConfig.yml
├── images
│ └── logo_32.png
├── index.md
└── toc.yml
├── build.sh
├── data
├── dead-band
│ ├── maxDelta.plt
│ ├── maxDelta_compressed.csv
│ ├── maxDelta_raw.csv
│ ├── trend.plt
│ ├── trend_compressed.csv
│ └── trend_raw.csv
└── swinging-door
│ ├── maxDelta.plt
│ ├── maxDelta_compressed.csv
│ ├── maxDelta_raw.csv
│ ├── trend.plt
│ ├── trend1.plt
│ ├── trend1_compressed.csv
│ ├── trend1_raw.csv
│ ├── trend2.plt
│ ├── trend2_compressed.csv
│ ├── trend2_raw.csv
│ ├── trend3.plt
│ ├── trend3_compressed.csv
│ ├── trend3_mini.plt
│ ├── trend3_mini_compressed.csv
│ ├── trend3_mini_raw.csv
│ ├── trend3_raw.csv
│ ├── trend_compressed.csv
│ └── trend_raw.csv
├── demos
├── .gitignore
├── Directory.Build.props
├── Dockerfiles
│ └── dotnet-gnuplot5
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── build.sh
├── gfoidl.DataCompression.Demos.Async
│ ├── Program.cs
│ └── gfoidl.DataCompression.Demos.Async.csproj
├── gfoidl.DataCompression.Demos.DeadBand.Stats
│ ├── Program.cs
│ ├── data
│ │ └── error.plt
│ └── gfoidl.DataCompression.Demos.DeadBand.Stats.csproj
├── gfoidl.DataCompression.Demos.DeadBand
│ ├── Program.cs
│ ├── data
│ │ ├── coolant-temp.csv
│ │ └── coolant-temp.plt
│ └── gfoidl.DataCompression.Demos.DeadBand.csproj
├── gfoidl.DataCompression.Demos.LiveData
│ ├── Program.cs
│ ├── data
│ │ ├── agt_n_awt1.csv
│ │ ├── agt_n_awt1.plt
│ │ ├── agt_zyl_6.csv
│ │ ├── agt_zyl_6.plt
│ │ ├── erregerspannung.csv
│ │ └── erregerspannung.plt
│ └── gfoidl.DataCompression.Demos.LiveData.csproj
├── gfoidl.DataCompression.Demos.SwingingDoor.Stats
│ ├── Program.cs
│ ├── data
│ │ └── error.plt
│ └── gfoidl.DataCompression.Demos.SwingingDoor.Stats.csproj
├── gfoidl.DataCompression.Demos.SwingingDoor
│ ├── Program.cs
│ ├── data
│ │ ├── coolant-temp.csv
│ │ └── coolant-temp.plt
│ └── gfoidl.DataCompression.Demos.SwingingDoor.csproj
├── gfoidl.DataCompression.Demos.sln
└── run.sh
├── gfoidl.DataCompression.sln
├── perf
├── .gitignore
├── Directory.Build.props
├── gfoidl.DataCompression.Benchmarks
│ ├── Base.cs
│ ├── Categories.cs
│ ├── DeadBandCompression.cs
│ ├── DeadBandCompressionAsync.cs
│ ├── Infrastructure
│ │ └── CompressionFactories.cs
│ ├── IteratorInstantiaton.cs
│ ├── Program.cs
│ ├── SwingingDoorCompression.cs
│ ├── SwingingDoorCompressionAsync.cs
│ ├── SwingingDoorCompressionIterator
│ │ └── SwingingDoorCompressionIteratorCloseTheDoorBenchmarks.cs
│ └── gfoidl.DataCompression.Benchmarks.csproj
├── gfoidl.DataCompression.ProfilingDemo
│ ├── Program.cs
│ └── gfoidl.DataCompression.ProfilingDemo.csproj
└── run-benchmarks.sh
├── source
├── Directory.Build.props
├── Directory.Build.targets
└── gfoidl.DataCompression
│ ├── Builders
│ ├── ArrayBuilder.cs
│ ├── ICollectionBuilder.cs
│ └── ListBuilder.cs
│ ├── Compression.cs
│ ├── Compression
│ ├── Compression.cd
│ ├── DeadBandCompression
│ │ ├── AsyncEnumerableIterator.cs
│ │ ├── DeadBandCompression.cs
│ │ ├── DeadBandCompressionIterator.cs
│ │ ├── IndexedIterator.cs
│ │ └── SequentialEnumerableIterator.cs
│ ├── Iterators.cd
│ ├── NoCompression
│ │ ├── AsyncEnumerableIterator.cs
│ │ ├── EnumerableIterator.cs
│ │ ├── NoCompression.cs
│ │ └── NoCompressionIterator.cs
│ └── SwingingDoorCompression
│ │ ├── AsyncEnumerableIterator.cs
│ │ ├── IndexedIterator.cs
│ │ ├── SequentialEnumerableIterator.cs
│ │ ├── SwingingDoorCompression.cs
│ │ └── SwingingDoorCompressionIterator.cs
│ ├── DataPoint.cs
│ ├── DataPointIndexedIterator.cs
│ ├── DataPointIterator.Async.cs
│ ├── DataPointIterator.Enumerable.cs
│ ├── DataPointIterator.cs
│ ├── DataPointSerializer.cs
│ ├── EmptyDataPointIterator.cs
│ ├── ExtensionMethods.cs
│ ├── ICompression.cs
│ ├── Strings.Designer.cs
│ ├── Strings.resx
│ ├── ThrowHelper.cs
│ ├── Wrappers
│ ├── ArrayWrapper.cs
│ └── ListWrapper.cs
│ └── gfoidl.DataCompression.csproj
└── tests
├── .editorconfig
├── Directory.Build.props
└── gfoidl.DataCompression.Tests
├── Builders
└── ArrayBuilderTests
│ ├── Add.cs
│ └── AddRange.cs
├── Compression
├── Base.cs
├── DeadBandCompressionTests
│ ├── Base.cs
│ ├── Clone.cs
│ ├── IteratorCaching.cs
│ ├── MoveNext.cs
│ ├── MoveNextAsync.cs
│ ├── ProcessAsyncCore.cs
│ ├── ProcessCore.cs
│ ├── ToArray.cs
│ ├── ToArrayAsync.cs
│ ├── ToList.cs
│ └── ToListAsync.cs
├── DisposeTests.cs
├── NoCompressionTests
│ ├── Base.cs
│ ├── Clone.cs
│ ├── MoveNext.cs
│ ├── MoveNextAsync.cs
│ ├── ProcessAsyncCore.cs
│ ├── ProcessCore.cs
│ ├── ToArray.cs
│ ├── ToArrayAsync.cs
│ ├── ToList.cs
│ └── ToListAsync.cs
└── SwingingDoorCompressionTests
│ ├── Base.cs
│ ├── Clone.cs
│ ├── IteratorCaching.cs
│ ├── MoveNext.cs
│ ├── MoveNextAsync.cs
│ ├── ProcessAsyncCore.cs
│ ├── ProcessCore.cs
│ ├── ToArray.cs
│ ├── ToArrayAsync.cs
│ ├── ToList.cs
│ └── ToListAsync.cs
├── Constants.cs
├── DataPointIteratorTests
└── Empty.cs
├── DataPointSerializerTests
└── Roundtrip.cs
├── DataPointTests
├── CalculatePoint.cs
├── Ctor.cs
├── Equals.cs
├── GetHashCode.cs
├── Gradient.cs
└── ToTimeValue.cs
├── ExtensionMethodsTests
├── Base.cs
├── DeadBandCompression.cs
├── NoCompression.cs
└── SwingingDoorCompression.cs
├── MySetUpClass.cs
├── Wrappers
├── ArrayWrapperTests
│ ├── Ctor.cs
│ ├── Indexer.cs
│ └── NotImplementedMembers.cs
└── ListWrapperTests
│ ├── Ctor.cs
│ ├── Indexer.cs
│ └── NotImplementedMembers.cs
└── gfoidl.DataCompression.Tests.csproj
/.azure/pipelines/ci-benchmarks.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | DOTNET_NOLOGO: 1
3 | DOTNET_CLI_TELEMETRY_OPTOUT: 1
4 | CI_BUILD_NUMBER: $(Build.BuildId)
5 | BRANCH_NAME: $(Build.SourceBranchName)
6 | TAG_NAME: $(Build.SourceBranchName)
7 |
8 | trigger: none
9 | # pr trigger must not be excluded, but in the UI for the pipeline definition a setting has to be made.
10 | # See https://docs.microsoft.com/en-us/azure/devops/pipelines/repos/github?view=azure-devops&tabs=yaml#comment-triggers
11 | # for further info.
12 |
13 | schedules:
14 | - cron: "0 5 * * *" # 05:00 each day
15 | displayName: "Daily build"
16 | branches:
17 | include:
18 | - master
19 |
20 | stages:
21 | - stage: Benchmarks
22 | jobs:
23 | - template: jobs/benchmarks.yml
24 |
--------------------------------------------------------------------------------
/.azure/pipelines/ci-demos.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | DOTNET_NOLOGO: 1
3 | DOTNET_CLI_TELEMETRY_OPTOUT: 1
4 | CI_BUILD_NUMBER: $(Build.BuildId)
5 | BRANCH_NAME: $(Build.SourceBranchName)
6 | TAG_NAME: $(Build.SourceBranchName)
7 |
8 | trigger: none
9 | # pr trigger must not be excluded, but in the UI for the pipeline definition a setting has to be made.
10 | # See https://docs.microsoft.com/en-us/azure/devops/pipelines/repos/github?view=azure-devops&tabs=yaml#comment-triggers
11 | # for further info.
12 |
13 | schedules:
14 | - cron: "15 4 * * *" # 04:15 each day
15 | displayName: "Daily build"
16 | branches:
17 | include:
18 | - master
19 |
20 | resources:
21 | containers:
22 | - container: dotnet-sdk-gnuplot5
23 | image: ghcr.io/gfoidl/datacompression/dotnet-gnuplot5
24 |
25 | stages:
26 | - stage: Demos
27 | jobs:
28 | - template: jobs/demos.yml
29 |
--------------------------------------------------------------------------------
/.azure/pipelines/ci-docs.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | DOTNET_NOLOGO: 1
3 | DOTNET_CLI_TELEMETRY_OPTOUT: 1
4 | CI_BUILD_NUMBER: $(Build.BuildId)
5 | BRANCH_NAME: $(Build.SourceBranchName)
6 | TAG_NAME: $(Build.SourceBranchName)
7 |
8 | # We don't need a CI trigger here, as the pipeline trigger starts this pipeline for master anyway.
9 | trigger: none
10 |
11 | resources:
12 | pipelines:
13 | - pipeline: ci-build
14 | source: DataCompression
15 | trigger:
16 | branches:
17 | include:
18 | - master
19 |
20 | stages:
21 | - stage: Build_Docs
22 | jobs:
23 | - template: jobs/build_docs.yml
24 |
25 | - stage: Deploy
26 | dependsOn:
27 | - Build_Docs
28 | condition: and( succeeded(), startsWith( variables['Build.SourceBranch'], 'refs/tags' ) )
29 | jobs:
30 | - template: jobs/deploy_docs.yml
31 |
--------------------------------------------------------------------------------
/.azure/pipelines/ci.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | DOTNET_NOLOGO: 1
3 | DOTNET_CLI_TELEMETRY_OPTOUT: 1
4 | CI_BUILD_NUMBER: $(Build.BuildId)
5 | BRANCH_NAME: $(Build.SourceBranchName)
6 | TAG_NAME: $(Build.SourceBranchName)
7 |
8 | trigger:
9 | - master
10 | - refs/tags/v*
11 |
12 | pr:
13 | branches:
14 | include:
15 | - master
16 |
17 | stages:
18 | - stage: Build_Test
19 | jobs:
20 | - template: jobs/build_and_test.yml
21 | parameters:
22 | # Need for tests .NET Framework 4.8
23 | name: windows
24 | vmImage: 'windows-2022'
25 |
26 | - stage: Code_Coverage
27 | dependsOn:
28 | - Build_Test
29 | jobs:
30 | - template: jobs/coverage.yml
31 |
32 | - stage: Deploy
33 | dependsOn:
34 | - Build_Test
35 | condition: and( succeeded(), startsWith( variables['Build.SourceBranch'], 'refs/tags' ) )
36 | jobs:
37 | - template: jobs/deploy_nuget.yml
38 |
--------------------------------------------------------------------------------
/.azure/pipelines/jobs/benchmarks.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | - job: benchmarks
3 | pool:
4 | vmImage: ubuntu-20.04
5 | steps:
6 | # ~SDKs already installed~
7 | - template: steps/dotnet-install.yml
8 |
9 | - bash: |
10 | cd perf/gfoidl.DataCompression.Benchmarks
11 | dotnet restore
12 | dotnet build -c Release --no-restore
13 | displayName: build
14 |
15 | - bash: |
16 | cd perf
17 | chmod +x run-benchmarks.sh
18 | ./run-benchmarks.sh
19 | displayName: run benchmarks
20 |
21 | - publish: perf/gfoidl.DataCompression.Benchmarks/BenchmarkDotNet.Artifacts/results
22 | artifact: bench-results
23 | displayName: publish benchmark results
24 |
--------------------------------------------------------------------------------
/.azure/pipelines/jobs/build_and_test.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | name: ''
3 | vmImage: ''
4 |
5 | jobs:
6 | - job: ${{ parameters.name }}_build
7 | displayName: '${{ parameters.name }} build and test'
8 | pool:
9 | vmImage: ${{ parameters.vmImage }}
10 | strategy:
11 | matrix:
12 | debug-build:
13 | BUILD_CONFIG: Debug
14 | release-build:
15 | BUILD_CONFIG: Release
16 | steps:
17 | # SDKs already installed
18 | #- template: steps/dotnet-install.yml
19 |
20 | - bash: |
21 | echo 'installed sdks:'
22 | dotnet --list-sdks
23 | echo "-------------------------------------------------"
24 | echo 'environment variables:'
25 | env | sort
26 |
27 | chmod u+x ./build.sh
28 | displayName: init
29 |
30 | - bash: ./build.sh build
31 | displayName: build
32 |
33 | # coverlet.msbuild must be added as package to the tests
34 | - bash: ./build.sh test-coverage
35 | displayName: test
36 |
37 | - task: PublishTestResults@2
38 | condition: always()
39 | inputs:
40 | testRunner: VSTest
41 | testResultsFiles: '**/*.trx'
42 |
43 | - bash: |
44 | cd tests/Coverage
45 |
46 | workDir="$(System.DefaultWorkingDirectory)"
47 |
48 | if [[ "$AGENT_OS" == "Windows_NT" ]]; then
49 | # Windows needs special treetment for the substitution due the \
50 | workDir="${workDir//\\/\\\\}\\\\"
51 | else
52 | workDir+="/"
53 | fi
54 |
55 | # Mac has a different sed, so special case it (hooray for standars ;-))
56 | if [[ "$AGENT_OS" != "Darwin" ]]; then
57 | sed -i 's|[^<]*|/|g' "Cobertura.xml"
58 | sed -i "s|${workDir}||g" "Cobertura.xml"
59 | else
60 | sed -i '' 's|[^<]+|/|g' "Cobertura.xml"
61 | sed -i '' "s|${workDir}||g" "Cobertura.xml"
62 | fi
63 | displayName: make Cobertura-paths relative
64 |
65 | # shortcut for PublishPipelineArtifact
66 | # Coverage report will be created later in a different stage
67 | - publish: tests/Coverage/Cobertura.xml
68 | artifact: 'Coverage-${{ parameters.name }}-${{ parameters.vmImage }}-$(BUILD_CONFIG)'
69 | displayName: publish artifact code coverage
70 |
71 | - bash: ./build.sh pack
72 | displayName: pack
73 | condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['BUILD_CONFIG'], 'Release'))
74 |
75 | - publish: 'NuGet-Packed'
76 | artifact: 'NuGet-Packed'
77 | condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['BUILD_CONFIG'], 'Release'), ne(variables['Build.Reason'], 'PullRequest'))
78 | displayName: publish artifact NuGet package
79 |
--------------------------------------------------------------------------------
/.azure/pipelines/jobs/build_docs.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | - job: docs_build
3 | pool:
4 | vmImage: 'windows-2022'
5 | steps:
6 | - bash: |
7 | export PATH="$(pwd)/dotnet:$PATH"
8 | echo 'installed sdks:'
9 | dotnet --list-sdks
10 | echo "-------------------------------------------------"
11 |
12 | chmod u+x ./build.sh
13 | ./build.sh build
14 | displayName: build
15 |
16 | - powershell: |
17 | choco install docfx -y
18 |
19 | if ($lastexitcode -ne 0) {
20 | throw ("Error generating document")
21 | }
22 | displayName: 'install docfx'
23 |
24 | - powershell: |
25 | cd api-doc
26 | docfx
27 |
28 | if ($lastexitcode -ne 0) {
29 | throw ("Error generating document")
30 | }
31 | displayName: 'docfx build'
32 |
33 | - publish: 'api-doc/_site'
34 | artifact: 'docs'
35 |
--------------------------------------------------------------------------------
/.azure/pipelines/jobs/coverage.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | - job: coverage_report_quality
3 | pool:
4 | vmImage: 'ubuntu-20.04'
5 | steps:
6 | # checkout is needed for file-references
7 | #- checkout: none
8 |
9 | - task: DownloadPipelineArtifact@2
10 | inputs:
11 | targetPath: './coverage'
12 |
13 | - task: PublishCodeCoverageResults@1
14 | inputs:
15 | codeCoverageTool: Cobertura
16 | summaryFileLocation: 'coverage/**/Cobertura.xml'
17 | pathToSources: $(System.DefaultWorkingDirectory)
18 |
19 | # extension from Marketplace https://marketplace.visualstudio.com/acquisition?itemName=mspremier.BuildQualityChecks
20 | - task: BuildQualityChecks@6
21 | displayName: 'Check build quality'
22 | inputs:
23 | checkCoverage: true
24 | coverageFailOption: 'build'
25 | coverageType: 'lines'
26 | allowCoverageVariance: true
27 | coverageVariance: '0.5'
28 | baseBranchRef: 'master'
29 |
--------------------------------------------------------------------------------
/.azure/pipelines/jobs/demos.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | - job: demos
3 | pool:
4 | vmImage: ubuntu-20.04
5 | container: dotnet-sdk-gnuplot5
6 | variables:
7 | SKIP_PLOT_DISPLAY: true
8 | steps:
9 | - bash: |
10 | cd demos
11 | dotnet restore
12 | dotnet build --no-restore
13 | displayName: build
14 |
15 | - bash: |
16 | cd demos
17 | chmod +x run.sh
18 | ./run.sh
19 | displayName: run demos
20 |
21 | - bash: |
22 | cd demos
23 | mkdir plots
24 |
25 | for plot in */**/*.png; do
26 | mv $plot plots
27 | done
28 |
29 | ls -la --color plots
30 | displayName: collect plots
31 |
32 | - publish: demos/plots
33 | artifact: plots
34 | displayName: publish plots
35 |
--------------------------------------------------------------------------------
/.azure/pipelines/jobs/deploy_docs.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | - job: deploy_docs
3 | pool:
4 | vmImage: 'ubuntu-20.04'
5 | variables:
6 | GH_USER: gfoidl
7 | GH_EMAIL: $(GITHUB_EMAIL)
8 | steps:
9 | - checkout: self
10 | persistCredentials: true
11 |
12 | - bash: |
13 | git config user.name $GH_USER
14 | git config user.email $GH_EMAIL
15 | displayName: '[git] Configure User'
16 |
17 | - bash: git checkout gh-pages
18 | displayName: '[git] Set development branch'
19 |
20 | - bash: git rm -rf .
21 | displayName: '[git] Clean working dir'
22 |
23 | - task: DownloadPipelineArtifact@2
24 | inputs:
25 | artifactName: 'docs'
26 | targetPath: './'
27 |
28 | - bash: |
29 | git add --all
30 | git commit -m "Pipelines-Bot: Updated site via $(Build.SourceVersion)"
31 | echo ""
32 | git log --oneline
33 | displayName: '[git] Creating commit'
34 |
35 | - bash: 'git push origin gh-pages'
36 | displayName: '[git] Push changes to remote'
37 |
--------------------------------------------------------------------------------
/.azure/pipelines/jobs/deploy_nuget.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | - job: deploy_nuget
3 | pool:
4 | vmImage: 'ubuntu-20.04'
5 | steps:
6 | - checkout: none
7 |
8 | - task: DownloadPipelineArtifact@2
9 | inputs:
10 | artifactName: 'NuGet-Packed'
11 | targetPath: './'
12 |
13 | - bash: |
14 | echo "NuGet-Packed:"
15 | ls -la .
16 |
17 | if [[ "$TAG_NAME" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)(-(preview-[0-9]+))$ ]]; then
18 | mkdir deploy_custom
19 |
20 | for package in ./*.*nupkg; do
21 | mv $package deploy_custom
22 | done
23 |
24 | echo "##vso[task.setvariable variable=deploy_custom;]1"
25 | elif [[ "$TAG_NAME" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
26 | mkdir deploy_nuget
27 |
28 | for package in ./*.*nupkg; do
29 | mv $package deploy_nuget
30 | done
31 |
32 | echo "##vso[task.setvariable variable=deploy_nuget;]1"
33 | else
34 | echo "no deploy, as $TAG_NAME does not match"
35 | echo ##vso[task.complete result=Skipped;]tag does not match for deploy
36 | fi
37 |
38 | echo "-------------------------------------------------"
39 | echo "custom:"
40 | ls -la deploy_custom
41 | echo "-------------------------------------------------"
42 | echo "nuget:"
43 | ls -la deploy_nuget
44 | echo "-------------------------------------------------"
45 | displayName: 'deploy to nuget / custom'
46 |
47 | - task: NuGetAuthenticate@0
48 | condition: eq(variables['deploy_custom'], '1')
49 |
50 | - task: NuGetCommand@2
51 | condition: eq(variables['deploy_custom'], '1')
52 | inputs:
53 | command: push
54 | packagesToPush: deploy_custom/*.nupkg
55 | nuGetFeedType: 'internal'
56 | publishVstsFeed: 'github-Projects/gfoidl-public'
57 | displayName: deploy to custom feed
58 |
59 | - task: NuGetCommand@2
60 | condition: eq(variables['deploy_nuget'], '1')
61 | inputs:
62 | command: push
63 | packagesToPush: deploy_nuget/*.nupkg
64 | nuGetFeedType: external
65 | publishFeedCredentials: 'nuget - gfoidl'
66 | displayName: deploy to nuget
67 |
--------------------------------------------------------------------------------
/.azure/pipelines/jobs/steps/dotnet-install.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - task: UseDotNet@2
3 | displayName: 'Use .NET SDK 6.0'
4 | inputs:
5 | version: 6.x
6 | includePreviewVersions: true
7 | installationPath: $(Agent.ToolsDirectory)/dotnet
8 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | #------------------------------------------------------------------------------
2 | # L I N E E N D I N G S
3 |
4 | # Set the default behavior, in case people don't have core.autocrlf set.
5 | * text=auto
6 |
7 | # Must keep LF line ending
8 | Dockerfile text eol=lf
9 | .dockerignore text eol=lf
10 |
11 | /**/*.sh text eol=lf
12 | /**/*.conf text eol=lf
13 | /**/*.crontab text eol=lf
14 | /**/*.yml text eol=lf
15 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @gfoidl
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [gfoidl]
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is. Ideally with stack-traces.
9 |
10 | ### Platform / Runtime
11 | - OS: [e.g. win-x64, linux-x64, mac-x64]
12 | - .NET version [run `dotnet --info`]
13 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 | Describe the changes this PR does (and why, link to issue, if any).
4 | If alternative solutions are evaluated, discuss them briefly.
5 |
6 | ## Benchmarks
7 |
8 | Show your benchmark results.
9 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 2
4 | 2
5 | 0
6 | 150
7 | dev
8 | gfoidl
9 | Foidl Günther
10 | gfoidl.DataCompression
11 | Copyright © Foidl Günther 2017-2021
12 | $(VersionMajor).$(VersionMinor).$(VersionPatch)
13 | $(VersionMajor).$(VersionMinor).$(BuildNumber).$(VersionPatch)
14 |
15 |
16 |
17 | latest
18 | net6.0
19 |
20 |
21 |
22 | $(MSBuildThisFileDirectory)NuGet-Packed
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017-2019 Günther M. FOIDL
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | | CI | Coverage | NuGet |
2 | | -- | -- | -- |
3 | | [](https://dev.azure.com/gh-gfoidl/github-Projects/_build/latest?definitionId=36&branchName=master) |  | [](https://www.nuget.org/packages/gfoidl.DataCompression/) |
4 |
5 | # gfoidl.DataCompression
6 |
7 | ## Algorithms
8 |
9 | * [Dead band](./api-doc/articles/DeadBand.md)
10 | * [Swinging Door](./api-doc/articles/SwingingDoor.md)
11 |
12 | ## Demos
13 |
14 | See `./demos` for code.
15 |
16 | _Note_: the graphs in the documentation are created by the code from `./demos`, so you can see which config-values got used.
17 |
18 | 
19 |
20 | 
21 |
22 | 
23 |
24 | ## Development channel
25 |
26 | To get packages from the development channel use a `nuget.config` similar to this one:
27 | ```xml
28 |
29 |
30 |
31 |
32 |
33 |
34 | ```
35 |
--------------------------------------------------------------------------------
/api-doc/.gitignore:
--------------------------------------------------------------------------------
1 | ###############
2 | # folder #
3 | ###############
4 | /**/DROP/
5 | /**/TEMP/
6 | /**/packages/
7 | /**/bin/
8 | /**/obj/
9 | _site
10 |
--------------------------------------------------------------------------------
/api-doc/api/.gitignore:
--------------------------------------------------------------------------------
1 | ###############
2 | # temp file #
3 | ###############
4 | *.yml
5 | .manifest
6 |
--------------------------------------------------------------------------------
/api-doc/api/index.md:
--------------------------------------------------------------------------------
1 | # PLACEHOLDER
2 | TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*!
3 |
--------------------------------------------------------------------------------
/api-doc/articles/DeadBand.md:
--------------------------------------------------------------------------------
1 | # Dead band
2 |
3 | ## Purpose
4 |
5 | Filtering noise caused by measure- or device-errors (i.e. instrument precision).
6 |
7 | ## Description
8 |
9 | Values that lie inbetween the dead band, defined by _ExDev_, get ommited because they are not meaningful.
10 | Decisions should not be based on these value. They are just noise, therefore they can be filtered out.
11 |
12 | 
13 |
14 | When a value is outside of the dead band, that value and the previous value are recored in order to maintain the trend.
15 |
16 | 
17 |
18 | ## Parameters
19 |
20 | | Name | Description |
21 | | ---- | ------------------------------------------------------- |
22 | | ExDev | (absolut) instrument precision |
23 | | ExMax | length of x/time before for sure a value gets recoreded |
24 |
25 | ## Examples
26 |
27 | ### Trend
28 |
29 | 
30 |
31 | ### Max Delta
32 |
33 | 
34 |
35 | ### Error and Statistics
36 |
37 | 
38 |
39 | | Data | # datapoints | average | sigma | skewness | kurtosis |
40 | | ---------- | ------------ | ------- | ------ | -------- | -------- |
41 | | raw | 1000 | 19.6584 | 0.1960 | -0.0330 | 2.3442 |
42 | | compressed | 490 | 19.6623 | 0.2007 | -0.1021 | 2.4672 |
43 |
44 | As can be seen statistics didn't change significantally, but the count of recorded datapoints was reduced -- by filtering noise -- by 51%.
45 |
46 | ## Literature
47 |
48 | * [OSIsoft: Exception and Compression Full Details](https://www.youtube.com/watch?v=89hg2mme7S0)
49 |
--------------------------------------------------------------------------------
/api-doc/articles/SwingingDoor.md:
--------------------------------------------------------------------------------
1 | # Swinging Door
2 |
3 | ## Purpose
4 |
5 | Data reduction by using the swinging door algorithm.
6 |
7 | ## Description
8 |
9 | 
10 |
11 | Beginning at the last archived value (1) and the next snapshots (2, 3, ...) a _swinging door_ is constructed, that is only allowed to close and not to open. Green area in the figure below.
12 |
13 | 
14 |
15 | When an incoming value (6) lies outside the allowed area, so the last snapshot (5) get stored, and beginning at this snapshot (5) a new _swinging door_ to the incoming (6) value gets opened.
16 | Therefore maintaining the trend in the data.
17 |
18 | ## Parameters
19 |
20 | | Name | Description |
21 | | ------- | ------------------------------------------------------------------------------ |
22 | | CompDev | (absolut) compression deviation |
23 | | ExMax | length of x/time before for sure a value gets recoreded |
24 | | ExMin | length of x/time within no value gets recorded (after the last archived value) |
25 |
26 | ## Examples
27 |
28 | ### Trend
29 |
30 | 
31 |
32 | ### Max Delta
33 |
34 | 
35 |
36 | ### Error and Statistics
37 |
38 | 
39 |
40 | | Data | # datapoints | average | sigma | skewness | kurtosis |
41 | | ---------- | ------------ | ------- | ------ | -------- | -------- |
42 | | raw | 1000 | 19.2854 | 1.2968 | -2.1689 | 7.0397 |
43 | | compressed | 418 | 19.2833 | 1.2984 | -2.1682 | 7.0428 |
44 |
45 | As can be seen statistics didn't change significantally, but the count of recorded datapoints was reduced -- by filtering noise -- by 58%.
46 |
47 | ## Literature
48 |
49 | * [OSIsoft: Exception and Compression Full Details](https://www.youtube.com/watch?v=89hg2mme7S0)
50 |
--------------------------------------------------------------------------------
/api-doc/articles/images/DeadBand_01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/DeadBand_01.jpg
--------------------------------------------------------------------------------
/api-doc/articles/images/DeadBand_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/DeadBand_02.png
--------------------------------------------------------------------------------
/api-doc/articles/images/dead-band_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/dead-band_error.png
--------------------------------------------------------------------------------
/api-doc/articles/images/dead-band_maxDelta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/dead-band_maxDelta.png
--------------------------------------------------------------------------------
/api-doc/articles/images/dead-band_trend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/dead-band_trend.png
--------------------------------------------------------------------------------
/api-doc/articles/images/demo_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/demo_01.png
--------------------------------------------------------------------------------
/api-doc/articles/images/demo_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/demo_02.png
--------------------------------------------------------------------------------
/api-doc/articles/images/demo_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/demo_03.png
--------------------------------------------------------------------------------
/api-doc/articles/images/swinging-door_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/swinging-door_01.png
--------------------------------------------------------------------------------
/api-doc/articles/images/swinging-door_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/swinging-door_02.png
--------------------------------------------------------------------------------
/api-doc/articles/images/swinging-door_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/swinging-door_error.png
--------------------------------------------------------------------------------
/api-doc/articles/images/swinging-door_maxDelta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/swinging-door_maxDelta.png
--------------------------------------------------------------------------------
/api-doc/articles/images/swinging-door_trend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/articles/images/swinging-door_trend.png
--------------------------------------------------------------------------------
/api-doc/articles/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Dead band
2 | href: DeadBand.md
3 |
4 | - name: Swinging Door
5 | href: SwingingDoor.md
6 |
--------------------------------------------------------------------------------
/api-doc/docfx.json:
--------------------------------------------------------------------------------
1 | {
2 | "metadata": [
3 | {
4 | "src": [
5 | {
6 | "cwd": "../",
7 | "files": [
8 | "source/**.csproj"
9 | ]
10 | }
11 | ],
12 | "dest": "api",
13 | "filter": "filterConfig.yml",
14 | "disableGitFeatures": false,
15 | "disableDefaultFilter": false
16 | }
17 | ],
18 | "build": {
19 | "content": [
20 | {
21 | "files": [
22 | "api/**.yml",
23 | "api/index.md"
24 | ]
25 | },
26 | {
27 | "files": [
28 | "articles/**.md",
29 | "articles/**/toc.yml",
30 | "toc.yml",
31 | "*.md"
32 | ]
33 | }
34 | ],
35 | "resource": [
36 | {
37 | "files": [
38 | "images/**",
39 | "articles/images/**"
40 | ]
41 | }
42 | ],
43 | "overwrite": [
44 | {
45 | "files": [
46 | "apidoc/**.md"
47 | ],
48 | "exclude": [
49 | "obj/**",
50 | "_site/**"
51 | ]
52 | }
53 | ],
54 | "globalMetadata": {
55 | "_appTitle": "gfoidl.DataCompression",
56 | "_appFooter": "Copyright © Foidl Günther 2017-2021",
57 | "_appLogoPath": "images/logo_32.png",
58 | "_appFaviconPath": "null"
59 | },
60 | "dest": "_site",
61 | "globalMetadataFiles": [],
62 | "fileMetadataFiles": [],
63 | "template": [
64 | "default"
65 | ],
66 | "postProcessors": [],
67 | "markdownEngineName": "markdig",
68 | "noLangKeyword": false,
69 | "keepFileLink": false,
70 | "cleanupCacheHistory": false,
71 | "disableGitFeatures": false
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/api-doc/filterConfig.yml:
--------------------------------------------------------------------------------
1 | apiRules:
2 | - exclude:
3 | uidRegex: ^gfoidl\.DataCompression\.Internal$
4 | type: Namespace
5 |
--------------------------------------------------------------------------------
/api-doc/images/logo_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfoidl/DataCompression/e47ae3d5bf2de70533c63aa1dd99971de1bd6340/api-doc/images/logo_32.png
--------------------------------------------------------------------------------
/api-doc/index.md:
--------------------------------------------------------------------------------
1 | # gfoidl.DataCompression
2 |
3 | ## Algorithms
4 |
5 | * [Dead band](./articles/DeadBand.md)
6 | * [Swinging Door](./articles/SwingingDoor.md)
7 |
8 | ## Demos
9 |
10 | See `./demos` for code.
11 |
12 | _Note_: the graphs in the documentation are created by the code from `./demos`, so you can see which config-values got used.
13 |
14 | 
15 |
16 | 
17 |
18 | 
19 |
--------------------------------------------------------------------------------
/api-doc/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Algorithms
2 | href: articles/
3 |
4 | - name: Api Documentation
5 | href: api/
6 | #homepage: api/index.md
7 |
--------------------------------------------------------------------------------
/data/dead-band/maxDelta.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 |
5 | set grid
6 | set title 'Dead band compression -- maxDelta'
7 | set xlabel 'Time'
8 | set ylabel 'Value'
9 | set key bottom right
10 |
11 | #set yrange [0.2:1.5]
12 |
13 | #set datafile separator ";"
14 |
15 | # replot is also possible for the second plot
16 | plot 'maxDelta_raw.csv' with linespoints title 'raw', \
17 | 'maxDelta_compressed.csv' with linespoints title 'compressed'
18 |
--------------------------------------------------------------------------------
/data/dead-band/maxDelta_compressed.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 0 0.5
3 | 4 0.6
4 | 6 0.5
5 | 7 1.25
6 | 9 1.3
7 |
--------------------------------------------------------------------------------
/data/dead-band/maxDelta_raw.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 0 0.5
3 | 1 0.6
4 | 2 0.4
5 | 3 0.55
6 | 4 0.6
7 | 5 0.4
8 | 6 0.5
9 | 7 1.25
10 | 8 1.2
11 | 9 1.3
12 |
--------------------------------------------------------------------------------
/data/dead-band/trend.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 |
5 | set grid
6 | set title 'Dead band compression -- Trend'
7 | set xlabel 'Time'
8 | set ylabel 'Value'
9 | set key bottom right
10 |
11 | set yrange [0.2:1.5]
12 |
13 | #set datafile separator ";"
14 |
15 | # replot is also possible for the second plot
16 | plot 'trend_raw.csv' with linespoints title 'raw', \
17 | 'trend_compressed.csv' with linespoints title 'compressed'
18 |
--------------------------------------------------------------------------------
/data/dead-band/trend_compressed.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 0 0.5
3 | 3 0.55
4 | 4 1.2
5 | 9 1.2
6 |
--------------------------------------------------------------------------------
/data/dead-band/trend_raw.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 0 0.5
3 | 1 0.6
4 | 2 0.4
5 | 3 0.55
6 | 4 1.2
7 | 5 1.1
8 | 6 1.3
9 | 7 1.25
10 | 8 1.2
11 | 9 1.2
12 |
--------------------------------------------------------------------------------
/data/swinging-door/maxDelta.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 |
5 | set grid
6 | set title 'Swinging door compression -- maxDelta'
7 | set xlabel 'Time'
8 | set ylabel 'Value'
9 | set key bottom right
10 | set xrange [0:21]
11 | set yrange [0:5]
12 |
13 | #set datafile separator ";"
14 |
15 | # replot is also possible for the second plot
16 | plot 'maxDelta_raw.csv' with linespoints title 'raw', \
17 | 'maxDelta_compressed.csv' with linespoints title 'compressed'
18 |
--------------------------------------------------------------------------------
/data/swinging-door/maxDelta_compressed.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 2 2
3 | 8 3.5
4 | 14 4
5 | 16 4.5
6 | 18 1.5
7 | 20 2.5
8 |
--------------------------------------------------------------------------------
/data/swinging-door/maxDelta_raw.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 2 2
3 | 4 3
4 | 6 3
5 | 8 3.5
6 | 10 3.5
7 | 12 4.5
8 | 14 4
9 | 16 4.5
10 | 18 1.5
11 | 20 2.5
12 |
--------------------------------------------------------------------------------
/data/swinging-door/trend.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 |
5 | set grid
6 | set title 'Swinging door compression -- Trend'
7 | set xlabel 'Time'
8 | set ylabel 'Value'
9 |
10 | set xrange [0:17]
11 | set yrange [0:6]
12 |
13 | #set datafile separator ";"
14 |
15 | # replot is also possible for the second plot
16 | plot 'trend_raw.csv' with linespoints title 'raw', \
17 | 'trend_compressed.csv' with linespoints title 'compressed'
18 |
--------------------------------------------------------------------------------
/data/swinging-door/trend1.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 |
5 | set grid
6 | set title 'Swinging door compression -- Trend1'
7 | set xlabel 'Time'
8 | set ylabel 'Value'
9 |
10 | set xrange [0:7.5]
11 | set yrange [0:2.5]
12 |
13 | set style line 2 lc rgb 'green' pt 9 # triangle
14 |
15 | #set datafile separator ";"
16 |
17 | # replot is also possible for the second plot
18 | plot 'trend1_raw.csv' with linespoints title 'raw', \
19 | 'trend1_compressed.csv' with points ls 2 title 'compressed'
20 |
--------------------------------------------------------------------------------
/data/swinging-door/trend1_compressed.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 0 1
3 | 2 1.2
4 | 4 2
5 | 6 2
6 | 7 1.2
7 |
--------------------------------------------------------------------------------
/data/swinging-door/trend1_raw.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 0 1
3 | 1 1.1
4 | 2 1.2
5 | 3 1.6
6 | 4 2
7 | 5 2
8 | 6 2
9 | 7 1.2
10 |
--------------------------------------------------------------------------------
/data/swinging-door/trend2.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 |
5 | set grid
6 | set title 'Swinging door compression -- Trend2'
7 | set xlabel 'Time'
8 | set ylabel 'Value'
9 |
10 | set xrange [0:7.5]
11 | set yrange [0:2.5]
12 |
13 | set style line 2 lc rgb 'green' pt 9 # triangle
14 |
15 | #set datafile separator ";"
16 |
17 | # replot is also possible for the second plot
18 | plot 'trend2_raw.csv' with linespoints title 'raw', \
19 | 'trend2_compressed.csv' with points ls 2 title 'compressed'
20 |
--------------------------------------------------------------------------------
/data/swinging-door/trend2_compressed.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 0 1
3 | 2 1.2
4 | 4 2
5 | 7 2
6 |
--------------------------------------------------------------------------------
/data/swinging-door/trend2_raw.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 0 1
3 | 1 1.1
4 | 2 1.2
5 | 3 1.6
6 | 4 2
7 | 5 2
8 | 6 2
9 | 7 2
10 |
--------------------------------------------------------------------------------
/data/swinging-door/trend3.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 |
5 | set grid
6 | set title 'Swinging door compression -- Trend3'
7 | set xlabel 'Time'
8 | set ylabel 'Value'
9 |
10 | set xrange [0:10]
11 | set yrange [-3:6]
12 |
13 | set style line 2 lc rgb 'green' pt 9 # triangle
14 |
15 | #set datafile separator ";"
16 |
17 | # replot is also possible for the second plot
18 | plot 'trend3_raw.csv' with linespoints title 'raw', \
19 | 'trend3_compressed.csv' with points ls 2 title 'compressed'
20 |
--------------------------------------------------------------------------------
/data/swinging-door/trend3_compressed.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 1 0
3 | 4 5
4 | 5 -2
5 | 6 5
6 | 8 3
7 | 9 5
8 |
--------------------------------------------------------------------------------
/data/swinging-door/trend3_mini.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 |
5 | set grid
6 | set title 'Swinging door compression -- Trend3 (minimal repro)'
7 | set xlabel 'Time'
8 | set ylabel 'Value'
9 |
10 | set xrange [4:10]
11 | set yrange [-3:6]
12 |
13 | set style line 2 lc rgb 'green' pt 9 # triangle
14 |
15 | #set datafile separator ";"
16 |
17 | # replot is also possible for the second plot
18 | plot 'trend3_mini_raw.csv' with linespoints title 'raw', \
19 | 'trend3_mini_compressed.csv' with points ls 2 title 'compressed'
20 |
--------------------------------------------------------------------------------
/data/swinging-door/trend3_mini_compressed.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 5 -2
3 | 6 5
4 | 8 3
5 | 9 5
6 |
--------------------------------------------------------------------------------
/data/swinging-door/trend3_mini_raw.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 5 -2
3 | 6 5
4 | 7 4
5 | 8 3
6 | 9 5
7 |
--------------------------------------------------------------------------------
/data/swinging-door/trend3_raw.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 1 0
3 | 2 1
4 | 3 2
5 | 4 5
6 | 5 -2
7 | 6 5
8 | 7 4
9 | 8 3
10 | 9 5
11 |
--------------------------------------------------------------------------------
/data/swinging-door/trend_compressed.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 2 2
3 | 8 3.5
4 | 10 5.5
5 | 14 1
6 | 16 1
7 |
--------------------------------------------------------------------------------
/data/swinging-door/trend_raw.csv:
--------------------------------------------------------------------------------
1 | #x y
2 | 2 2
3 | 4 3
4 | 6 2.5
5 | 8 3.5
6 | 10 5.5
7 | 12 2.5
8 | 14 1
9 | 16 1
10 |
--------------------------------------------------------------------------------
/demos/.gitignore:
--------------------------------------------------------------------------------
1 | *.csv
2 | *.png
3 |
--------------------------------------------------------------------------------
/demos/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Exe
7 | enable
8 |
9 |
10 |
11 | $(DefineConstants);SKIP_PLOT_DISPLAY;CI_BUILD
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/demos/Dockerfiles/dotnet-gnuplot5/.dockerignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | build.sh
3 |
--------------------------------------------------------------------------------
/demos/Dockerfiles/dotnet-gnuplot5/Dockerfile:
--------------------------------------------------------------------------------
1 | # .NET Core 6 SDK + gnuplot 5
2 |
3 | FROM mcr.microsoft.com/dotnet/sdk:6.0
4 |
5 | LABEL org.opencontainers.image.source https://github.com/gfoidl/DataCompression
6 |
7 | RUN apt update \
8 | && apt install -y gnuplot \
9 | && rm -rf /var/lib/apt/lists/* /tmp/*
10 |
--------------------------------------------------------------------------------
/demos/Dockerfiles/dotnet-gnuplot5/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | docker build -t ghcr.io/gfoidl/datacompression/dotnet-gnuplot5 .
4 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.Async/Program.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Runtime.CompilerServices;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace gfoidl.DataCompression.Demos.Async
10 | {
11 | class Program
12 | {
13 | static async Task Main(string[] args)
14 | {
15 | #if CI_BUILD
16 | var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
17 | #else
18 | var cts = new CancellationTokenSource();
19 | #endif
20 | IAsyncEnumerable source = Source(cts.Token);
21 | //DataPointIterator filtered = source.DeadBandCompressionAsync(0.01);
22 | DataPointIterator filtered = source.SwingingDoorCompressionAsync(0.01);
23 | ValueTask sinkTask = Sink(filtered, cts.Token);
24 |
25 | #if !CI_BUILD
26 | Console.WriteLine("any key to stop...");
27 | Console.ReadKey();
28 | cts.Cancel();
29 | #endif
30 |
31 | double sum = default;
32 | try
33 | {
34 | sum = await sinkTask;
35 | }
36 | catch (OperationCanceledException) { }
37 |
38 | Console.WriteLine($"sum: {sum}");
39 | }
40 | //---------------------------------------------------------------------
41 | private static async IAsyncEnumerable Source([EnumeratorCancellation] CancellationToken ct = default)
42 | {
43 | await Task.Yield();
44 |
45 | int i = 0;
46 | var rnd = new Random(42);
47 |
48 | while (!ct.IsCancellationRequested)
49 | {
50 | await Task.Yield();
51 | double x = i++;
52 | double y = rnd.NextDouble();
53 |
54 | yield return new DataPoint(x, y);
55 | }
56 | }
57 | //---------------------------------------------------------------------
58 | private static async ValueTask Sink(DataPointIterator data, CancellationToken ct = default)
59 | {
60 | await Task.Yield();
61 |
62 | double sum = 0;
63 | uint count = 0;
64 |
65 | await foreach (DataPoint dp in data.WithCancellation(ct))
66 | {
67 | sum += dp.Y;
68 |
69 | if (count % (1 << 15) == 0)
70 | {
71 | Console.WriteLine($"count: {count}, sum: {sum}");
72 | }
73 | count++;
74 | }
75 |
76 | return sum;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.Async/gfoidl.DataCompression.Demos.Async.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(StandardTfm)
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.DeadBand.Stats/data/error.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | set term pngcairo size 1200,1000 enhanced
4 | set output 'error-deadband.png'
5 |
6 | set multiplot layout 4, 1 title "Error for dead band compression\n"
7 |
8 | unset title
9 | set grid
10 | set key top right
11 |
12 | set ytics 10.0
13 | plot 'result.csv' using 1:2 with lines title 'raw'
14 | plot 'compressed.csv' with dots title 'compressed'
15 | plot 'result.csv' using 1:3 with lines title 'compressed reconstructed'
16 |
17 | #set xlabel 'x'
18 | set ytics 0.2
19 | set yrange [-0.3:0.3]
20 | plot 'result.csv' using 1:4 with lines title 'error'
21 |
22 | unset multiplot
23 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.DeadBand.Stats/gfoidl.DataCompression.Demos.DeadBand.Stats.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(StandardTfm)
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.DeadBand/Program.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.IO;
7 |
8 | namespace gfoidl.DataCompression.Demos.DeadBand
9 | {
10 | static class Program
11 | {
12 | static void Main()
13 | {
14 | Environment.CurrentDirectory = Path.Combine(Directory.GetCurrentDirectory(), "data");
15 |
16 | var dataPointReader = new DataPointSerializer();
17 |
18 | IEnumerable compressed = dataPointReader
19 | .Read("coolant-temp.csv")
20 | .DeadBandCompression(1d);
21 |
22 | dataPointReader.Write("coolant-temp_compressed.csv", compressed, header: ("Oh", "Temp"));
23 |
24 | GnuPlot();
25 | ShowChart();
26 | }
27 | //---------------------------------------------------------------------
28 | private static void GnuPlot()
29 | {
30 | var gnuPlot = new Process();
31 | //gnuPlot.StartInfo.WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "data");
32 | gnuPlot.StartInfo.FileName = "gnuplot";
33 | gnuPlot.StartInfo.Arguments = "coolant-temp.plt";
34 | gnuPlot.Start();
35 | gnuPlot.WaitForExit();
36 | }
37 | //---------------------------------------------------------------------
38 | private static void ShowChart()
39 | {
40 | #if !SKIP_PLOT_DISPLAY
41 | var png = new Process();
42 | png.StartInfo.UseShellExecute = true; // defaults to false in in .NET (Core)
43 | png.StartInfo.FileName = "coolant-temp-deadband.png";
44 | png.Start();
45 | #endif
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.DeadBand/data/coolant-temp.csv:
--------------------------------------------------------------------------------
1 | # Oh Temp [°C]
2 | 27830 86
3 | 28332 85
4 | 28641 85
5 | 29135 85
6 | 29749 83
7 | 29940 84
8 | 30743 83
9 | 31266 80
10 | 31384 80
11 | 31943 84
12 | 32039 84
13 | 32728 87
14 | 32775 85
15 | 33415 86
16 | 34157 87
17 | 34351 88
18 | 34610 86
19 | 35291 86
20 | 36061 82
21 | 36584 82
22 | 36630 82
23 | 37305 82
24 | 37398 82
25 | 38103 83
26 | 38643 83
27 | 38886 82
28 | 38930 82
29 | 39570 82
30 | 40249 83
31 | 40747 83
32 | 40890 89
33 | 41671 87
34 | 42343 86
35 | 42530 88
36 | 42812 86
37 | 42831 88
38 | 42973 88
39 | 43158 89
40 | 43828 86
41 | 44287 86
42 | 44618 86
43 | 45048 83
44 | 45188 86
45 | 46145 86
46 | 46817 85
47 | 46970 86
48 | 47127 86
49 | 47315 86
50 | 48153 84
51 | 48154 81
52 | 48851 82
53 | 48868 81
54 | 49181 83
55 | 49681 85
56 | 50196 83
57 | 50197 83
58 | 50976 85
59 | 51310 85
60 | 51693 85
61 | 52126 81
62 | 52939 80
63 | 52985 80
64 | 53746 80
65 | 54178 80
66 | 54345 80
67 | 54849 80
68 | 55109 79
69 | 55250 79
70 | 55762 79
71 | 56238 79
72 | 56523 79
73 | 56993 84
74 | 57278 84
75 | 57618 83
76 | 57730 83
77 | 57849 84
78 | 58013 83
79 | 58348 86
80 | 58755 85
81 | 59395 82
82 | 60167 79
83 | 60333 79
84 | 60667 78
85 | 60862 78
86 | 61313 76
87 | 61640 78
88 | 62236 78
89 | 62712 71
90 | 62733 78
91 | 62877 79
92 | 63065 80
93 | 63701 82
94 | 63960 82
95 | 64373 81
96 | 65032 84
97 | 65613 79
98 | 65633 83
99 | 65951 81
100 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.DeadBand/data/coolant-temp.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 | set term pngcairo size 800,600 enhanced
5 | set output 'coolant-temp-deadband.png'
6 |
7 | set grid
8 | set title 'Coolant temp over Oh'
9 | set xlabel 'Oh'
10 | set ylabel 'temp [°C]'
11 | set key bottom right
12 |
13 | #set datafile separator ";"
14 |
15 | # replot is also possible for the second plot
16 | plot 'coolant-temp.csv' with linespoints title 'raw', \
17 | 'coolant-temp_compressed.csv' with linespoints title 'compressed'
18 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.DeadBand/gfoidl.DataCompression.Demos.DeadBand.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(StandardTfm)
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.LiveData/Program.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.IO;
7 |
8 | namespace gfoidl.DataCompression.Demos.LiveData
9 | {
10 | static class Program
11 | {
12 | static void Main()
13 | {
14 | Environment.CurrentDirectory = Path.Combine(Directory.GetCurrentDirectory(), "data");
15 |
16 | Run("agt_n_awt1", 0.25, 0.5);
17 | #if !CI_BUILD
18 | Console.WriteLine("hit key to continue...");
19 | Console.ReadKey();
20 | #endif
21 |
22 | Run("agt_zyl_6", 0.75, 1.5);
23 | #if !CI_BUILD
24 | Console.WriteLine("hit key to continue...");
25 | Console.ReadKey();
26 | #endif
27 |
28 | Run("erregerspannung", 0.4, 0.8);
29 | #if !CI_BUILD
30 | Console.WriteLine("hit key to continue...");
31 | Console.ReadKey();
32 | #endif
33 | }
34 | //---------------------------------------------------------------------
35 | private static void Run(string name, double instrumentPrecision, double compressionDeviation)
36 | {
37 | var dataPointReader = new DataPointSerializer();
38 |
39 | IEnumerable compressed = dataPointReader
40 | .Read($"{name}.csv", dateTimeFormat: "yyyy-MM-dd_HH:mm:ss")
41 | .DeadBandCompression(instrumentPrecision)
42 | .SwingingDoorCompression(compressionDeviation);
43 |
44 | dataPointReader.Write($"{name}_compressed.csv", compressed, dateTimeFormat: "yyyy-MM-dd_HH:mm:ss");
45 |
46 | GnuPlot(name);
47 | ShowChart(name);
48 | }
49 | //---------------------------------------------------------------------
50 | private static void GnuPlot(string name)
51 | {
52 | var gnuPlot = new Process();
53 | //gnuPlot.StartInfo.WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "data");
54 | gnuPlot.StartInfo.FileName = "gnuplot";
55 | gnuPlot.StartInfo.Arguments = $"{name}.plt";
56 | gnuPlot.Start();
57 | gnuPlot.WaitForExit();
58 | }
59 | //---------------------------------------------------------------------
60 | private static void ShowChart(string name)
61 | {
62 | #if !SKIP_PLOT_DISPLAY
63 | var png = new Process();
64 | png.StartInfo.UseShellExecute = true; // defaults to false in .NET (Core)
65 | png.StartInfo.FileName = $"{name}.png";
66 | png.Start();
67 | #endif
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.LiveData/data/agt_n_awt1.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 | set term pngcairo size 1200,600 enhanced
5 | set output 'agt_n_awt1.png'
6 |
7 | set grid
8 | set title 'AGT n AWT1'
9 | set xlabel 'Time'
10 | set ylabel '[°C]'
11 | #set key bottom right
12 |
13 | set xdata time
14 | set timefmt "%Y-%m-%d_%H:%M:%S"
15 | set format x "%H:%M"
16 |
17 | #set datafile separator ";"
18 |
19 | # replot is also possible for the second plot
20 | plot 'agt_n_awt1.csv' using 1:2 with lines title 'raw', \
21 | 'agt_n_awt1_compressed.csv' using 1:2 with lines title 'compressed'
22 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.LiveData/data/agt_zyl_6.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 | set term pngcairo size 1200,600 enhanced
5 | set output 'agt_zyl_6.png'
6 |
7 | set grid
8 | set title 'AGT Zyl. 6'
9 | set xlabel 'Time'
10 | set ylabel '[°C]'
11 | #set key bottom right
12 |
13 | #set yrange [14:25]
14 |
15 | set xdata time
16 | set timefmt "%Y-%m-%d_%H:%M:%S"
17 | set format x "%H:%M"
18 |
19 | #set datafile separator ";"
20 |
21 | # replot is also possible for the second plot
22 | plot 'agt_zyl_6.csv' using 1:2 with lines title 'raw', \
23 | 'agt_zyl_6_compressed.csv' using 1:2 with lines title 'compressed'
24 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.LiveData/data/erregerspannung.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 | set term pngcairo size 1200,600 enhanced
5 | set output 'erregerspannung.png'
6 |
7 | set grid
8 | set title 'Erregerspannung'
9 | set xlabel 'Time'
10 | set ylabel '[V]'
11 | set key bottom right
12 |
13 | set yrange [14:25]
14 |
15 | set xdata time
16 | set timefmt "%Y-%m-%d_%H:%M:%S"
17 | set format x "%H:%M"
18 |
19 | #set datafile separator ";"
20 |
21 | # replot is also possible for the second plot
22 | plot 'erregerspannung.csv' using 1:2 with lines title 'raw', \
23 | 'erregerspannung_compressed.csv' using 1:2 with lines title 'compressed'
24 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.LiveData/gfoidl.DataCompression.Demos.LiveData.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(StandardTfm)
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.SwingingDoor.Stats/data/error.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | set term pngcairo size 1200,1000 enhanced
4 | set output 'error-swingingdoor.png'
5 |
6 | set multiplot layout 4, 1 title "Error for swinging door compression\n"
7 |
8 | unset title
9 | set grid
10 | set key top right
11 |
12 | set ytics 10.0
13 | plot 'result.csv' using 1:2 with lines title 'raw'
14 | plot 'compressed.csv' with dots title 'compressed'
15 | plot 'result.csv' using 1:3 with lines title 'compressed reconstructed'
16 |
17 | #set xlabel 'x'
18 | set ytics 0.2
19 | set yrange [-0.3:0.3]
20 | plot 'result.csv' using 1:4 with lines title 'error'
21 |
22 | unset multiplot
23 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.SwingingDoor.Stats/gfoidl.DataCompression.Demos.SwingingDoor.Stats.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(StandardTfm)
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.SwingingDoor/Program.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.IO;
7 |
8 | namespace gfoidl.DataCompression.Demos.SwingingDoor
9 | {
10 | static class Program
11 | {
12 | static void Main()
13 | {
14 | Environment.CurrentDirectory = Path.Combine(Directory.GetCurrentDirectory(), "data");
15 |
16 | var dataPointReader = new DataPointSerializer();
17 |
18 | IEnumerable compressed = dataPointReader
19 | .Read("coolant-temp.csv")
20 | .SwingingDoorCompression(1.5);
21 |
22 | dataPointReader.Write("coolant-temp_compressed.csv", compressed, header: ("Oh", "Temp"));
23 |
24 | GnuPlot();
25 | ShowChart();
26 | }
27 | //---------------------------------------------------------------------
28 | private static void GnuPlot()
29 | {
30 | var gnuPlot = new Process();
31 | //gnuPlot.StartInfo.WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "data");
32 | gnuPlot.StartInfo.FileName = "gnuplot";
33 | gnuPlot.StartInfo.Arguments = "coolant-temp.plt";
34 | gnuPlot.Start();
35 | gnuPlot.WaitForExit();
36 | }
37 | //---------------------------------------------------------------------
38 | private static void ShowChart()
39 | {
40 | #if !SKIP_PLOT_DISPLAY
41 | var png = new Process();
42 | png.StartInfo.UseShellExecute = true; // defaults to false in .NET (Core)
43 | png.StartInfo.FileName = "coolant-temp-swingingdoor.png";
44 | png.Start();
45 | #endif
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.SwingingDoor/data/coolant-temp.csv:
--------------------------------------------------------------------------------
1 | # Oh Temp [°C]
2 | 27830 86
3 | 28332 85
4 | 28641 85
5 | 29135 85
6 | 29749 83
7 | 29940 84
8 | 30743 83
9 | 31266 80
10 | 31384 80
11 | 31943 84
12 | 32039 84
13 | 32728 87
14 | 32775 85
15 | 33415 86
16 | 34157 87
17 | 34351 88
18 | 34610 86
19 | 35291 86
20 | 36061 82
21 | 36584 82
22 | 36630 82
23 | 37305 82
24 | 37398 82
25 | 38103 83
26 | 38643 83
27 | 38886 82
28 | 38930 82
29 | 39570 82
30 | 40249 83
31 | 40747 83
32 | 40890 89
33 | 41671 87
34 | 42343 86
35 | 42530 88
36 | 42812 86
37 | 42831 88
38 | 42973 88
39 | 43158 89
40 | 43828 86
41 | 44287 86
42 | 44618 86
43 | 45048 83
44 | 45188 86
45 | 46145 86
46 | 46817 85
47 | 46970 86
48 | 47127 86
49 | 47315 86
50 | 48153 84
51 | 48154 81
52 | 48851 82
53 | 48868 81
54 | 49181 83
55 | 49681 85
56 | 50196 83
57 | 50197 83
58 | 50976 85
59 | 51310 85
60 | 51693 85
61 | 52126 81
62 | 52939 80
63 | 52985 80
64 | 53746 80
65 | 54178 80
66 | 54345 80
67 | 54849 80
68 | 55109 79
69 | 55250 79
70 | 55762 79
71 | 56238 79
72 | 56523 79
73 | 56993 84
74 | 57278 84
75 | 57618 83
76 | 57730 83
77 | 57849 84
78 | 58013 83
79 | 58348 86
80 | 58755 85
81 | 59395 82
82 | 60167 79
83 | 60333 79
84 | 60667 78
85 | 60862 78
86 | 61313 76
87 | 61640 78
88 | 62236 78
89 | 62712 71
90 | 62733 78
91 | 62877 79
92 | 63065 80
93 | 63701 82
94 | 63960 82
95 | 64373 81
96 | 65032 84
97 | 65613 79
98 | 65633 83
99 | 65951 81
100 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.SwingingDoor/data/coolant-temp.plt:
--------------------------------------------------------------------------------
1 | reset
2 |
3 | #set terminal dumb
4 | set term pngcairo size 800,600 enhanced
5 | set output 'coolant-temp-swingingdoor.png'
6 |
7 | set grid
8 | set title 'Coolant temp over Oh'
9 | set xlabel 'Oh'
10 | set ylabel 'temp [°C]'
11 | set key bottom right
12 |
13 | #set datafile separator ";"
14 |
15 | # replot is also possible for the second plot
16 | plot 'coolant-temp.csv' with linespoints title 'raw', \
17 | 'coolant-temp_compressed.csv' with linespoints title 'compressed'
18 |
--------------------------------------------------------------------------------
/demos/gfoidl.DataCompression.Demos.SwingingDoor/gfoidl.DataCompression.Demos.SwingingDoor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(StandardTfm)
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demos/run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | for demoProject in ./**/*.csproj; do
4 | echo ""
5 | echo "-------------------------------------------------"
6 | echo "Running demo '$(basename $demoProject .csproj)'"
7 |
8 | cd $(dirname $demoProject)
9 | dotnet run --no-build
10 | cd - >/dev/null
11 | done
12 |
--------------------------------------------------------------------------------
/perf/.gitignore:
--------------------------------------------------------------------------------
1 | BenchmarkDotNet.Artifacts
2 |
--------------------------------------------------------------------------------
/perf/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Exe
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/Base.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using BenchmarkDotNet.Attributes;
7 |
8 | namespace gfoidl.DataCompression.Benchmarks;
9 |
10 | [MemoryDiagnoser]
11 | public abstract class Base
12 | {
13 | private const int Count = 1_000_000;
14 |
15 | private readonly Random _rnd = new(Seed: 42);
16 | //-------------------------------------------------------------------------
17 | protected IEnumerable Source(int count = Count)
18 | {
19 | for (int i = 0; i < count; ++i)
20 | {
21 | double x = i;
22 | double y = _rnd!.NextDouble();
23 |
24 | yield return (x, y);
25 | }
26 | }
27 | //-------------------------------------------------------------------------
28 | protected async IAsyncEnumerable SourceAsync(int count = Count)
29 | {
30 | foreach (DataPoint dataPoint in this.Source(count))
31 | {
32 | await Task.Yield();
33 | yield return dataPoint;
34 | }
35 | }
36 | //-------------------------------------------------------------------------
37 | protected static double Consume(DataPointIterator iterator)
38 | {
39 | double sum = 0;
40 |
41 | foreach (DataPoint dataPoint in iterator)
42 | {
43 | sum += dataPoint.Y;
44 | }
45 |
46 | return sum;
47 | }
48 | //-------------------------------------------------------------------------
49 | protected static async ValueTask ConsumeAsync(DataPointIterator iterator)
50 | {
51 | double sum = 0;
52 |
53 | await foreach (DataPoint dataPoint in iterator)
54 | {
55 | sum += dataPoint.Y;
56 | }
57 |
58 | return sum;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/Categories.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | namespace gfoidl.DataCompression.Benchmarks;
4 |
5 | public static class Categories
6 | {
7 | public const string Compression = nameof(Compression);
8 | public const string Sync = nameof(Sync);
9 | public const string Async = nameof(Async);
10 | public const string Deadband = nameof(Deadband);
11 | public const string SwingingDoor = nameof(SwingingDoor);
12 | }
13 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/DeadBandCompression.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using BenchmarkDotNet.Attributes;
5 |
6 | namespace gfoidl.DataCompression.Benchmarks;
7 |
8 | [BenchmarkCategory(Categories.Compression, Categories.Sync, Categories.Deadband)]
9 | public class DeadBandCompression : Base
10 | {
11 | [Benchmark]
12 | public double Enumerate()
13 | {
14 | IEnumerable source = this.Source();
15 | using DataPointIterator filtered = source.DeadBandCompression(0.1);
16 | return Consume(filtered);
17 | }
18 | //-------------------------------------------------------------------------
19 | [Benchmark]
20 | public DataPoint[] ToArray()
21 | {
22 | IEnumerable source = this.Source();
23 | using DataPointIterator filtered = source.DeadBandCompression(0.1);
24 | return filtered.ToArray();
25 | }
26 | //-------------------------------------------------------------------------
27 | [Benchmark]
28 | public List ToList()
29 | {
30 | IEnumerable source = this.Source();
31 | using DataPointIterator filtered = source.DeadBandCompression(0.1);
32 | return filtered.ToList();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/DeadBandCompressionAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using BenchmarkDotNet.Attributes;
6 |
7 | namespace gfoidl.DataCompression.Benchmarks;
8 |
9 | [BenchmarkCategory(Categories.Compression, Categories.Async, Categories.Deadband)]
10 | public class DeadBandCompressionAsync : Base
11 | {
12 | [Benchmark]
13 | public async ValueTask Enumerate()
14 | {
15 | IAsyncEnumerable source = this.SourceAsync();
16 | using DataPointIterator filtered = source.DeadBandCompressionAsync(0.1);
17 | return await ConsumeAsync(filtered);
18 | }
19 | //---------------------------------------------------------------------
20 | [Benchmark]
21 | public async ValueTask ToArray()
22 | {
23 | IAsyncEnumerable source = this.SourceAsync();
24 | using DataPointIterator filtered = source.DeadBandCompressionAsync(0.1);
25 | return await filtered.ToArrayAsync();
26 | }
27 | //---------------------------------------------------------------------
28 | [Benchmark]
29 | public async ValueTask> ToList()
30 | {
31 | IAsyncEnumerable source = this.SourceAsync();
32 | using DataPointIterator filtered = source.DeadBandCompressionAsync(0.1);
33 | return await filtered.ToListAsync();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/Infrastructure/CompressionFactories.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | namespace gfoidl.DataCompression.Benchmarks.Infrastructure
4 | {
5 | public interface ICompressionFactory
6 | {
7 | ICompression Create();
8 | }
9 | //-------------------------------------------------------------------------
10 | public class DeadBandCompressionFactory : ICompressionFactory
11 | {
12 | public ICompression Create() => new DataCompression.DeadBandCompression(0.1);
13 | }
14 | //-------------------------------------------------------------------------
15 | public class SwingingDoorCompressionFactory : ICompressionFactory
16 | {
17 | public ICompression Create() => new DataCompression.SwingingDoorCompression(0.1);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/IteratorInstantiaton.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using BenchmarkDotNet.Attributes;
6 | using gfoidl.DataCompression.Benchmarks.Infrastructure;
7 |
8 | namespace gfoidl.DataCompression.Benchmarks;
9 |
10 | [BenchmarkCategory("Instantiation")]
11 | [ShortRunJob] // Care only about allocations
12 | [GenericTypeArguments(typeof(DeadBandCompressionFactory))]
13 | [GenericTypeArguments(typeof(SwingingDoorCompressionFactory))]
14 | public class IteratorInstantiaton : Base where TFactory : ICompressionFactory, new()
15 | {
16 | private const int OperationsForMultiple = 1_000;
17 | private const int Count = 2;
18 |
19 | private readonly DataPoint[] _dataPoints = { new DataPoint((0, 1)), new DataPoint((1, 0)) };
20 | private readonly ICompression _compression;
21 | //---------------------------------------------------------------------
22 | public IteratorInstantiaton()
23 | {
24 | TFactory factory = new();
25 | _compression = factory.Create();
26 | }
27 | //---------------------------------------------------------------------
28 | [Benchmark]
29 | public double SingleIteration()
30 | {
31 | using DataPointIterator iterator = _compression.Process(_dataPoints);
32 | return Consume(iterator);
33 | }
34 | //---------------------------------------------------------------------
35 | [Benchmark]
36 | public async ValueTask SingleIterationASync()
37 | {
38 | IAsyncEnumerable source = this.SourceAsync(Count);
39 | using DataPointIterator iterator = _compression.ProcessAsync(source);
40 | return await ConsumeAsync(iterator);
41 | }
42 | //---------------------------------------------------------------------
43 | [Benchmark(OperationsPerInvoke = OperationsForMultiple)]
44 | public double MultipleIterations()
45 | {
46 | double sum = 0;
47 |
48 | for (int i = 0; i < OperationsForMultiple; ++i)
49 | {
50 | using DataPointIterator iterator = _compression.Process(_dataPoints);
51 | sum += Consume(iterator);
52 | }
53 |
54 | return sum;
55 | }
56 | //---------------------------------------------------------------------
57 | [Benchmark(OperationsPerInvoke = OperationsForMultiple)]
58 | public async ValueTask MultipleIterationsAsync()
59 | {
60 | double sum = 0;
61 |
62 | for (int i = 0; i < OperationsForMultiple; ++i)
63 | {
64 | IAsyncEnumerable source = this.SourceAsync(Count);
65 | using DataPointIterator iterator = _compression.ProcessAsync(source);
66 | sum += await ConsumeAsync(iterator);
67 | }
68 |
69 | return sum;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/Program.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using BenchmarkDotNet.Running;
4 | using gfoidl.DataCompression.Benchmarks;
5 |
6 | BenchmarkSwitcher.FromAssembly(typeof(Base).Assembly).Run(args);
7 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/SwingingDoorCompression.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using BenchmarkDotNet.Attributes;
5 |
6 | namespace gfoidl.DataCompression.Benchmarks;
7 |
8 | [BenchmarkCategory(Categories.Compression, Categories.Sync, Categories.SwingingDoor)]
9 | public class SwingingDoorCompression : Base
10 | {
11 | [Benchmark]
12 | public double Enumerate()
13 | {
14 | IEnumerable source = this.Source();
15 | using DataPointIterator filtered = source.SwingingDoorCompression(0.1);
16 | return Consume(filtered);
17 | }
18 | //---------------------------------------------------------------------
19 | [Benchmark]
20 | public DataPoint[] ToArray()
21 | {
22 | IEnumerable source = this.Source();
23 | using DataPointIterator filtered = source.SwingingDoorCompression(0.1);
24 | return filtered.ToArray();
25 | }
26 | //---------------------------------------------------------------------
27 | [Benchmark]
28 | public List ToList()
29 | {
30 | IEnumerable source = this.Source();
31 | using DataPointIterator filtered = source.SwingingDoorCompression(0.1);
32 | return filtered.ToList();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/SwingingDoorCompressionAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using BenchmarkDotNet.Attributes;
6 |
7 | namespace gfoidl.DataCompression.Benchmarks;
8 |
9 | [BenchmarkCategory(Categories.Compression, Categories.Async, Categories.SwingingDoor)]
10 | public class SwingingDoorCompressionAsync : Base
11 | {
12 | [Benchmark]
13 | public async ValueTask Enumerate()
14 | {
15 | IAsyncEnumerable source = this.SourceAsync();
16 | using DataPointIterator filtered = source.SwingingDoorCompressionAsync(0.1);
17 | return await ConsumeAsync(filtered);
18 | }
19 | //---------------------------------------------------------------------
20 | [Benchmark]
21 | public async ValueTask ToArray()
22 | {
23 | IAsyncEnumerable source = this.SourceAsync();
24 | using DataPointIterator filtered = source.SwingingDoorCompressionAsync(0.1);
25 | return await filtered.ToArrayAsync();
26 | }
27 | //---------------------------------------------------------------------
28 | [Benchmark]
29 | public async ValueTask> ToList()
30 | {
31 | IAsyncEnumerable source = this.SourceAsync();
32 | using DataPointIterator filtered = source.SwingingDoorCompressionAsync(0.1);
33 | return await filtered.ToListAsync();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.Benchmarks/gfoidl.DataCompression.Benchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(StandardTfm)
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.ProfilingDemo/Program.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace gfoidl.DataCompression.ProfilingDemo
10 | {
11 | static class Program
12 | {
13 | private static readonly DataPoint[] s_dataPoints;
14 | private static List s_compressed = new List(1000);
15 | //---------------------------------------------------------------------
16 | static Program()
17 | {
18 | Random rnd = new Random();
19 | s_dataPoints = new DataPoint[1000];
20 |
21 | for (int i = 0; i < s_dataPoints.Length; ++i)
22 | {
23 | s_dataPoints[i] = new DataPoint(i, rnd.NextDouble());
24 | }
25 | }
26 | //---------------------------------------------------------------------
27 | static async Task Main()
28 | {
29 | using CancellationTokenSource cts = new CancellationTokenSource();
30 | int counter = 0;
31 |
32 | Task t = Task.Run(() =>
33 | {
34 | // A single instance can be re-used over and over again
35 | DeadBandCompression deadBand = new DeadBandCompression(0.1);
36 | SwingingDoorCompression swingingDoor = new SwingingDoorCompression(0.1);
37 |
38 | while (!cts.IsCancellationRequested)
39 | {
40 | s_compressed.Clear();
41 | counter++;
42 |
43 | // Allocates a new instance of compression each iteration
44 | //DataPointIterator compressed = s_dataPoints//.Select(d => d)
45 | // //.DeadBandCompression(0.05)
46 | // .SwingingDoorCompression(0.1);
47 |
48 | //DataPointIterator compressed = compression.Process(s_dataPoints.Select(d => d));
49 | DataPointIterator deadBandCompressed = deadBand.Process(s_dataPoints);
50 | DataPointIterator swingingDoorCompressed = swingingDoor.Process(deadBandCompressed);
51 |
52 | foreach (DataPoint item in swingingDoorCompressed)
53 | {
54 | s_compressed.Add(item);
55 | }
56 |
57 | Console.Write(".");
58 | }
59 | }, cts.Token);
60 |
61 | Console.WriteLine("any key to stop...");
62 | Console.ReadKey();
63 |
64 | cts.Cancel();
65 |
66 | try
67 | {
68 | await t;
69 | }
70 | catch (OperationCanceledException)
71 | { }
72 |
73 | Console.WriteLine($"\n\nend -- counter: {counter}");
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/perf/gfoidl.DataCompression.ProfilingDemo/gfoidl.DataCompression.ProfilingDemo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(StandardTfm)
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/perf/run-benchmarks.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | cd gfoidl.DataCompression.Benchmarks
6 |
7 | # Running the benchmarks via --allCategories is much easier than via --filter and globbing.
8 | dotnet run -c Release --no-build --allCategories Compression Sync --join
9 | dotnet run -c Release --no-build --allCategories Compression Async --join
10 | dotnet run -c Release --no-build --allCategories Instantiation --join
11 |
--------------------------------------------------------------------------------
/source/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | enable
7 | true
8 |
9 |
10 |
11 | https://gfoidl.github.io/DataCompression
12 | https://github.com/gfoidl/DataCompression
13 | MIT
14 | ReadMe.md
15 | git
16 | true
17 |
18 |
19 |
20 | true
21 |
22 |
23 |
24 | true
25 | $(NoWarn);CS1591
26 |
27 |
28 |
29 | embedded
30 |
31 |
32 | true
33 | snupkg
34 | true
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/source/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Builders/ICollectionBuilder.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | namespace gfoidl.DataCompression.Builders
4 | {
5 | internal interface ICollectionBuilder
6 | {
7 | void Add(T item);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Builders/ListBuilder.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 |
5 | namespace gfoidl.DataCompression.Builders
6 | {
7 | internal struct ListBuilder : ICollectionBuilder
8 | {
9 | private readonly List _list;
10 | //---------------------------------------------------------------------
11 | public ListBuilder(bool initialize) => _list = new List();
12 | //---------------------------------------------------------------------
13 | public void Add(T item) => _list.Add(item);
14 | //---------------------------------------------------------------------
15 | public readonly List ToList() => _list;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace gfoidl.DataCompression
7 | {
8 | ///
9 | /// Defines the interface for the compression algorithms.
10 | ///
11 | public abstract class Compression : ICompression
12 | {
13 | private protected readonly double? _maxDeltaX;
14 | private protected readonly double? _minDeltaX;
15 | //---------------------------------------------------------------------
16 | ///
17 | /// Creates a new instance of .
18 | ///
19 | ///
20 | /// Length of x before for sure a value gets recoreded. See .
21 | ///
22 | ///
23 | /// Length of x/time within no value gets recorded (after the last archived value).
24 | /// See .
25 | ///
26 | protected Compression(double? maxDeltaX = null, double? minDeltaX = null)
27 | {
28 | _maxDeltaX = maxDeltaX;
29 | _minDeltaX = minDeltaX;
30 | }
31 | //---------------------------------------------------------------------
32 | ///
33 | public abstract bool ArchiveIncoming { get; }
34 | //---------------------------------------------------------------------
35 | ///
36 | public double? MaxDeltaX => _maxDeltaX;
37 | //---------------------------------------------------------------------
38 | ///
39 | public double? MinDeltaX => _minDeltaX;
40 | //---------------------------------------------------------------------
41 | ///
42 | public DataPointIterator Process(IEnumerable data)
43 | {
44 | if (data is null) ThrowHelper.ThrowArgumentNull(ThrowHelper.ExceptionArgument.data);
45 |
46 | return this.ProcessCore(data);
47 | }
48 | //---------------------------------------------------------------------
49 | #if NETSTANDARD2_1
50 | ///
51 | public DataPointIterator ProcessAsync(IAsyncEnumerable data)
52 | {
53 | if (data is null) ThrowHelper.ThrowArgumentNull(ThrowHelper.ExceptionArgument.data);
54 |
55 | return this.ProcessAsyncCore(data);
56 | }
57 | #endif
58 | //---------------------------------------------------------------------
59 | ///
60 | /// Implementation of the compression / filtering.
61 | ///
62 | /// Input data
63 | /// The compressed / filtered data.
64 | protected abstract DataPointIterator ProcessCore(IEnumerable data);
65 | //---------------------------------------------------------------------
66 | #if NETSTANDARD2_1
67 | ///
68 | /// Implementation of the compression / filtering.
69 | ///
70 | /// Input data
71 | /// The compressed / filtered data.
72 | protected abstract DataPointIterator ProcessAsyncCore(IAsyncEnumerable data);
73 | #endif
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/Compression.cd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | IAEAAAAAAAEAYAAAAgAAAAAAAAAEAAAAAAAAAAEAEAA=
7 | Compression.cs
8 |
9 |
10 |
11 |
12 |
13 |
14 | IAAAAAACAAAAAAAAIAAAAAAAAAAAAAAAAEAAAAAEEAA=
15 | Compression\DeadBandCompression\DeadBandCompression.cs
16 |
17 |
18 |
19 |
20 |
21 | IAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAEAA=
22 | Compression\NoCompression\NoCompression.cs
23 |
24 |
25 |
26 |
27 |
28 | IAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAEAEAAAEEAA=
29 | Compression\SwingingDoorCompression\SwingingDoorCompression.cs
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/DeadBandCompression/AsyncEnumerableIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Threading;
7 |
8 | namespace gfoidl.DataCompression.Internal.DeadBand
9 | {
10 | internal sealed class AsyncEnumerableIterator : DeadBandCompressionIterator
11 | {
12 | public void SetData(DeadBandCompression deadBandCompression, IAsyncEnumerable source)
13 | {
14 | this.SetData(deadBandCompression as Compression, source);
15 | _deadBandCompression = deadBandCompression;
16 | }
17 | //---------------------------------------------------------------------
18 | public override DataPointIterator Clone() => throw new NotSupportedException();
19 | public override bool MoveNext() => throw new NotSupportedException();
20 | public override DataPoint[] ToArray() => throw new NotSupportedException();
21 | public override List ToList() => throw new NotSupportedException();
22 | //---------------------------------------------------------------------
23 | protected override void DisposeCore()
24 | {
25 | Debug.Assert(_deadBandCompression is not null);
26 |
27 | ref AsyncEnumerableIterator? cache = ref _deadBandCompression._cachedAsyncEnumerableIterator;
28 | Interlocked.CompareExchange(ref cache, this, null);
29 |
30 | base.DisposeCore();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/DeadBandCompression/DeadBandCompressionIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Diagnostics;
5 | using System.Runtime.CompilerServices;
6 |
7 | namespace gfoidl.DataCompression.Internal.DeadBand
8 | {
9 | internal abstract class DeadBandCompressionIterator : DataPointIterator
10 | {
11 | protected DeadBandCompression? _deadBandCompression;
12 | protected (double Min, double Max) _bounding;
13 | //---------------------------------------------------------------------
14 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
15 | protected void GetBounding(in DataPoint dataPoint)
16 | {
17 | Debug.Assert(_deadBandCompression is not null);
18 |
19 | double y = dataPoint.Y;
20 |
21 | // Produces better code than updating _bounding directly
22 | ref (double Min, double Max) bounding = ref _bounding;
23 |
24 | bounding.Min = y - _deadBandCompression.InstrumentPrecision;
25 | bounding.Max = y + _deadBandCompression.InstrumentPrecision;
26 | }
27 | //---------------------------------------------------------------------
28 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
29 | protected internal sealed override ref (bool Archive, bool MaxDelta) IsPointToArchive(in DataPoint incoming, in DataPoint lastArchived)
30 | {
31 | ref (bool Archive, bool MaxDelta) archive = ref _archive;
32 |
33 | if (!this.IsMaxDeltaX(ref archive, lastArchived.X, incoming.X))
34 | {
35 | archive.Archive = incoming.Y < _bounding.Min || _bounding.Max < incoming.Y;
36 | }
37 |
38 | return ref archive;
39 | }
40 | //---------------------------------------------------------------------
41 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
42 | private void UpdatePoints(in DataPoint incoming)
43 | {
44 | if (!_archive.MaxDelta)
45 | {
46 | this.GetBounding(incoming);
47 | }
48 | }
49 | //---------------------------------------------------------------------
50 | protected internal sealed override void Init(in DataPoint incoming) => this.UpdatePoints(incoming);
51 |
52 | // Override even if empty body, but this type is sealed so the virtual dispatch could be
53 | // eliminated by the JIT.
54 | protected internal sealed override void UpdateFilters(in DataPoint incoming, in DataPoint lastArchived) { }
55 | //---------------------------------------------------------------------
56 | protected override void DisposeCore()
57 | {
58 | _deadBandCompression = null;
59 | _bounding = default;
60 |
61 | base.DisposeCore();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/DeadBandCompression/IndexedIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace gfoidl.DataCompression.Internal.DeadBand
10 | {
11 | internal sealed class IndexedIterator : DeadBandCompressionIterator
12 | where TList : IList
13 | {
14 | private readonly DataPointIndexedIterator _inner = new();
15 | private TList? _list;
16 | //---------------------------------------------------------------------
17 | public void SetData(DeadBandCompression deadBandCompression, TList source)
18 | {
19 | Debug.Assert(source is not null);
20 |
21 | this.SetData(deadBandCompression);
22 | _deadBandCompression = deadBandCompression;
23 | _list = source;
24 |
25 | _inner.SetData(deadBandCompression, this, source);
26 | }
27 | //---------------------------------------------------------------------
28 | public override DataPointIterator Clone()
29 | {
30 | Debug.Assert(_deadBandCompression is not null);
31 | Debug.Assert(_list is not null);
32 |
33 | IndexedIterator clone = new();
34 | clone.SetData(_deadBandCompression, _list);
35 |
36 | return clone;
37 | }
38 | //---------------------------------------------------------------------
39 | public override DataPointIterator GetEnumerator() => _inner!.GetEnumerator();
40 | public override DataPoint[] ToArray() => _inner!.ToArray();
41 | public override List ToList() => _inner!.ToList();
42 | public override bool MoveNext() => throw new InvalidOperationException("Should operate on _inner");
43 | //---------------------------------------------------------------------
44 | #if NETSTANDARD2_1
45 | public override ValueTask ToArrayAsync(CancellationToken ct) => throw new NotSupportedException();
46 | public override ValueTask> ToListAsync(CancellationToken ct) => throw new NotSupportedException();
47 | #endif
48 | //---------------------------------------------------------------------
49 | protected override void DisposeCore()
50 | {
51 | if (_state == DisposedState)
52 | {
53 | return;
54 | }
55 |
56 | Debug.Assert(_deadBandCompression is not null);
57 |
58 | //_inner?.Dispose(); !!! don't dispose _inner, as _inner disposes this instance
59 |
60 | _list = default;
61 |
62 | ref DataPointIterator? cache = ref _deadBandCompression._cachedIndexedIterator;
63 | Interlocked.CompareExchange(ref cache, this, null);
64 |
65 | base.DisposeCore();
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/DeadBandCompression/SequentialEnumerableIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace gfoidl.DataCompression.Internal.DeadBand
10 | {
11 | internal sealed class SequentialEnumerableIterator : DeadBandCompressionIterator
12 | {
13 | public void SetData(DeadBandCompression deadBandCompression, IEnumerable source)
14 | {
15 | this.SetData(deadBandCompression as Compression, source);
16 | _deadBandCompression = deadBandCompression;
17 | }
18 | //---------------------------------------------------------------------
19 | public override DataPointIterator Clone()
20 | {
21 | Debug.Assert(_deadBandCompression is not null);
22 | Debug.Assert(_source is not null);
23 |
24 | SequentialEnumerableIterator clone = new();
25 | clone.SetData(_deadBandCompression, _source);
26 |
27 | return clone;
28 | }
29 | //---------------------------------------------------------------------
30 | #if NETSTANDARD2_1
31 | public override ValueTask ToArrayAsync(CancellationToken ct) => throw new NotSupportedException();
32 | public override ValueTask> ToListAsync(CancellationToken ct) => throw new NotSupportedException();
33 | #endif
34 | //---------------------------------------------------------------------
35 | protected override void DisposeCore()
36 | {
37 | if (_state == DisposedState)
38 | {
39 | return;
40 | }
41 |
42 | Debug.Assert(_deadBandCompression is not null);
43 |
44 | ref SequentialEnumerableIterator? cache = ref _deadBandCompression._cachedSequentialEnumerableIterator;
45 | Interlocked.CompareExchange(ref cache, this, null);
46 |
47 | base.DisposeCore();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/NoCompression/AsyncEnumerableIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace gfoidl.DataCompression.Internal.NoCompression
10 | {
11 | internal sealed class AsyncEnumerableIterator : NoCompressionIterator
12 | {
13 | public override IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
14 | => this.IterateCore(cancellationToken);
15 | //---------------------------------------------------------------------
16 | private async IAsyncEnumerator IterateCore(CancellationToken cancellationToken)
17 | {
18 | Debug.Assert(_asyncSource != null);
19 |
20 | await foreach (DataPoint dataPoint in _asyncSource.WithCancellation(cancellationToken).ConfigureAwait(false))
21 | {
22 | yield return dataPoint;
23 | }
24 | }
25 | //---------------------------------------------------------------------
26 | private protected override async ValueTask BuildCollectionAsync(TBuilder builder, CancellationToken cancellationToken)
27 | {
28 | await foreach (DataPoint dataPoint in _asyncSource.WithCancellation(cancellationToken).ConfigureAwait(false))
29 | {
30 | builder.Add(dataPoint);
31 | }
32 | }
33 | //---------------------------------------------------------------------
34 | public override DataPointIterator Clone() => throw new NotSupportedException();
35 | public override bool MoveNext() => throw new NotSupportedException();
36 | public override DataPoint[] ToArray() => throw new NotSupportedException();
37 | public override List ToList() => throw new NotSupportedException();
38 | protected internal override void Init(in DataPoint incoming) => throw new NotSupportedException();
39 | protected internal override ref (bool Archive, bool MaxDelta) IsPointToArchive(in DataPoint incoming, in DataPoint lastArchived) => throw new NotSupportedException();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/NoCompression/EnumerableIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using gfoidl.DataCompression.Builders;
9 |
10 | namespace gfoidl.DataCompression.Internal.NoCompression
11 | {
12 | internal sealed class EnumerableIterator : NoCompressionIterator
13 | {
14 | public override DataPointIterator Clone()
15 | {
16 | Debug.Assert(_algorithm is not null);
17 | Debug.Assert(_source is not null);
18 |
19 | EnumerableIterator clone = new();
20 | clone.SetData(_algorithm, _source);
21 |
22 | return clone;
23 | }
24 | //---------------------------------------------------------------------
25 | public override bool MoveNext()
26 | {
27 | if (_state == InitialState || _enumerator == null)
28 | ThrowHelper.ThrowInvalidOperation(ThrowHelper.ExceptionResource.GetEnumerator_must_be_called_first);
29 |
30 | if (_enumerator.MoveNext())
31 | {
32 | _lastArchived = _enumerator.Current;
33 | return true;
34 | }
35 |
36 | return false;
37 | }
38 | //---------------------------------------------------------------------
39 | public override DataPoint[] ToArray()
40 | {
41 | Debug.Assert(_source != null);
42 |
43 | var arrayBuilder = new ArrayBuilder(true);
44 | arrayBuilder.AddRange(_source);
45 |
46 | return arrayBuilder.ToArray();
47 | }
48 | //---------------------------------------------------------------------
49 | public override List ToList() => new List(_source);
50 | //---------------------------------------------------------------------
51 | protected internal override void Init(in DataPoint incoming) => throw new NotSupportedException();
52 | protected internal override ref (bool Archive, bool MaxDelta) IsPointToArchive(in DataPoint incoming, in DataPoint lastArchived) => throw new NotSupportedException();
53 | //---------------------------------------------------------------------
54 | #if NETSTANDARD2_1
55 | public override ValueTask ToArrayAsync(CancellationToken ct) => throw new NotSupportedException();
56 | public override ValueTask> ToListAsync(CancellationToken ct) => throw new NotSupportedException();
57 | #endif
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/NoCompression/NoCompression.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using gfoidl.DataCompression.Internal.NoCompression;
5 |
6 | namespace gfoidl.DataCompression
7 | {
8 | ///
9 | /// A filter that performs no compression
10 | ///
11 | public sealed class NoCompression : Compression
12 | {
13 | internal static readonly NoCompression s_instance = new NoCompression();
14 | //---------------------------------------------------------------------
15 | ///
16 | public override bool ArchiveIncoming => true;
17 | //-------------------------------------------------------------------------
18 | ///
19 | protected override DataPointIterator ProcessCore(IEnumerable data)
20 | {
21 | EnumerableIterator iter = new();
22 | iter.SetData(this, data);
23 |
24 | return iter;
25 | }
26 | //---------------------------------------------------------------------
27 | #if NETSTANDARD2_1
28 | ///
29 | /// Implementation of the compression / filtering.
30 | ///
31 | /// Input data
32 | /// The compressed / filtered data.
33 | protected override DataPointIterator ProcessAsyncCore(IAsyncEnumerable data)
34 | {
35 | AsyncEnumerableIterator iter = new();
36 | iter.SetData(this, data);
37 |
38 | return iter;
39 | }
40 | #endif
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/NoCompression/NoCompressionIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | namespace gfoidl.DataCompression.Internal.NoCompression
4 | {
5 | internal abstract class NoCompressionIterator : DataPointIterator
6 | { }
7 | }
8 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/SwingingDoorCompression/AsyncEnumerableIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Threading;
7 |
8 | namespace gfoidl.DataCompression.Internal.SwingingDoor
9 | {
10 | internal sealed class AsyncEnumerableIterator : SwingingDoorCompressionIterator
11 | {
12 | public void SetData(SwingingDoorCompression swingingDoorCompression, IAsyncEnumerable source)
13 | {
14 | this.SetData(swingingDoorCompression as Compression, source);
15 | _swingingDoorCompression = swingingDoorCompression;
16 | }
17 | //---------------------------------------------------------------------
18 | public override DataPointIterator Clone() => throw new NotSupportedException();
19 | public override bool MoveNext() => throw new NotSupportedException();
20 | public override DataPoint[] ToArray() => throw new NotSupportedException();
21 | public override List ToList() => throw new NotSupportedException();
22 | //---------------------------------------------------------------------
23 | protected override void DisposeCore()
24 | {
25 | Debug.Assert(_swingingDoorCompression is not null);
26 |
27 | ref AsyncEnumerableIterator? cache = ref _swingingDoorCompression._cachedAsyncEnumerableIterator;
28 | Interlocked.CompareExchange(ref cache, this, null);
29 |
30 | base.DisposeCore();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/SwingingDoorCompression/IndexedIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace gfoidl.DataCompression.Internal.SwingingDoor
10 | {
11 | internal sealed class IndexedIterator : SwingingDoorCompressionIterator
12 | where TList : IList
13 | {
14 | private readonly DataPointIndexedIterator _inner = new();
15 | private TList? _list;
16 | //---------------------------------------------------------------------
17 | public void SetData(SwingingDoorCompression swingingDoorCompression, TList source)
18 | {
19 | Debug.Assert(source is not null);
20 |
21 | this.SetData(swingingDoorCompression);
22 | _swingingDoorCompression = swingingDoorCompression;
23 | _list = source;
24 |
25 | _inner.SetData(swingingDoorCompression, this, source);
26 | }
27 | //---------------------------------------------------------------------
28 | public override DataPointIterator Clone()
29 | {
30 | Debug.Assert(_swingingDoorCompression is not null);
31 | Debug.Assert(_list is not null);
32 |
33 | IndexedIterator clone = new();
34 | clone.SetData(_swingingDoorCompression, _list);
35 |
36 | return clone;
37 | }
38 | //---------------------------------------------------------------------
39 | public override DataPointIterator GetEnumerator() => _inner!.GetEnumerator();
40 | public override DataPoint[] ToArray() => _inner!.ToArray();
41 | public override List ToList() => _inner!.ToList();
42 | public override bool MoveNext() => throw new InvalidOperationException("Should operate on _inner");
43 | //---------------------------------------------------------------------
44 | #if NETSTANDARD2_1
45 | public override ValueTask ToArrayAsync(CancellationToken ct) => throw new NotSupportedException();
46 | public override ValueTask> ToListAsync(CancellationToken ct) => throw new NotSupportedException();
47 | #endif
48 | //---------------------------------------------------------------------
49 | protected override void DisposeCore()
50 | {
51 | if (_state == DisposedState)
52 | {
53 | return;
54 | }
55 |
56 | Debug.Assert(_swingingDoorCompression is not null);
57 |
58 | //_inner?.Dispose(); !!! don't dispose _inner, as _inner disposes this instance
59 |
60 | _list = default;
61 |
62 | ref DataPointIterator? cache = ref _swingingDoorCompression._cachedIndexedIterator;
63 | Interlocked.CompareExchange(ref cache, this, null);
64 |
65 | base.DisposeCore();
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/SwingingDoorCompression/SequentialEnumerableIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace gfoidl.DataCompression.Internal.SwingingDoor
10 | {
11 | internal sealed class SequentialEnumerableIterator : SwingingDoorCompressionIterator
12 | {
13 | public void SetData(SwingingDoorCompression swingingDoorCompression, IEnumerable source)
14 | {
15 | this.SetData(swingingDoorCompression as Compression, source);
16 | _swingingDoorCompression = swingingDoorCompression;
17 | }
18 | //---------------------------------------------------------------------
19 | public override DataPointIterator Clone()
20 | {
21 | Debug.Assert(_swingingDoorCompression is not null);
22 | Debug.Assert(_source is not null);
23 |
24 | SequentialEnumerableIterator clone = new();
25 | clone.SetData(_swingingDoorCompression, _source);
26 |
27 | return clone;
28 | }
29 | //---------------------------------------------------------------------
30 | #if NETSTANDARD2_1
31 | public override ValueTask ToArrayAsync(CancellationToken ct) => throw new NotSupportedException();
32 | public override ValueTask> ToListAsync(CancellationToken ct) => throw new NotSupportedException();
33 | #endif
34 | //---------------------------------------------------------------------
35 | protected override void DisposeCore()
36 | {
37 | if (_state == DisposedState)
38 | {
39 | return;
40 | }
41 |
42 | Debug.Assert(_swingingDoorCompression is not null);
43 |
44 | ref SequentialEnumerableIterator? cache = ref _swingingDoorCompression._cachedSequentialEnumerableIterator;
45 | Interlocked.CompareExchange(ref cache, this, null);
46 |
47 | base.DisposeCore();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Compression/SwingingDoorCompression/SwingingDoorCompressionIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Runtime.CompilerServices;
4 | using System;
5 | using System.Diagnostics;
6 |
7 | namespace gfoidl.DataCompression.Internal.SwingingDoor
8 | {
9 | internal abstract class SwingingDoorCompressionIterator : DataPointIterator
10 | {
11 | protected static readonly (double Max, double Min) s_newDoor = (double.PositiveInfinity, double.NegativeInfinity);
12 | //---------------------------------------------------------------------
13 | protected SwingingDoorCompression? _swingingDoorCompression;
14 | protected (double Max, double Min) _slope;
15 | //---------------------------------------------------------------------
16 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
17 | protected internal sealed override ref (bool Archive, bool MaxDelta) IsPointToArchive(in DataPoint incoming, in DataPoint lastArchived)
18 | {
19 | ref (bool Archive, bool MaxDelta) archive = ref _archive;
20 |
21 | if (!this.IsMaxDeltaX(ref archive, lastArchived.X, incoming.X))
22 | {
23 | // Better to compare via gradient (1 calculation) than comparing to allowed y-values (2 calcuations)
24 | // Obviously, the result should be the same ;-)
25 | double slopeToIncoming = lastArchived.Gradient(incoming);
26 | archive.Archive = slopeToIncoming < _slope.Min || _slope.Max < slopeToIncoming;
27 | }
28 |
29 | return ref archive;
30 | }
31 | //---------------------------------------------------------------------
32 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 | protected void CloseTheDoor(in DataPoint incoming, in DataPoint lastArchived)
34 | {
35 | Debug.Assert(_swingingDoorCompression is not null);
36 |
37 | double delta_x = incoming.X - lastArchived.X;
38 |
39 | if (delta_x > 0)
40 | {
41 | double delta_y = incoming.Y - lastArchived.Y;
42 | double delta_yUpper = delta_y + _swingingDoorCompression.CompressionDeviation;
43 | double delta_yLower = delta_y - _swingingDoorCompression.CompressionDeviation;
44 |
45 | double upperSlope = delta_yUpper / delta_x;
46 | double lowerSlope = delta_yLower / delta_x;
47 |
48 | if (upperSlope < _slope.Max) _slope.Max = upperSlope;
49 | if (lowerSlope > _slope.Min) _slope.Min = lowerSlope;
50 | }
51 | else
52 | {
53 | GradientEquality(incoming, lastArchived);
54 | }
55 |
56 | [MethodImpl(MethodImplOptions.NoInlining)]
57 | void GradientEquality(in DataPoint incoming, in DataPoint lastArchived)
58 | {
59 | double upperSlope = lastArchived.GradientEquality(incoming, return0OnEquality: true);
60 | double lowerSlope = lastArchived.GradientEquality(incoming, return0OnEquality: true);
61 |
62 | if (upperSlope < _slope.Max) _slope.Max = upperSlope;
63 | if (lowerSlope > _slope.Min) _slope.Min = lowerSlope;
64 | }
65 | }
66 | //---------------------------------------------------------------------
67 | private void OpenNewDoor() => _slope = s_newDoor;
68 | //---------------------------------------------------------------------
69 | protected internal sealed override void Init(in DataPoint incoming) => this.OpenNewDoor();
70 | protected internal sealed override void UpdateFilters(in DataPoint incoming, in DataPoint lastArchived) => this.CloseTheDoor(incoming, lastArchived);
71 | //---------------------------------------------------------------------
72 | protected override void DisposeCore()
73 | {
74 | _swingingDoorCompression = null;
75 | _slope = default;
76 |
77 | base.DisposeCore();
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/EmptyDataPointIterator.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace gfoidl.DataCompression
9 | {
10 | internal sealed class EmptyDataPointIterator : DataPointIterator
11 | {
12 | public override DataPointIterator Clone() => this;
13 | public override bool MoveNext() => false;
14 | public override DataPoint[] ToArray() => Array.Empty();
15 | public override List ToList() => new List();
16 | //---------------------------------------------------------------------
17 | #if NETSTANDARD2_1
18 | public override ValueTask ToArrayAsync(CancellationToken ct) => new ValueTask(Array.Empty());
19 | public override ValueTask> ToListAsync(CancellationToken ct) => new ValueTask>(new List());
20 | #endif
21 | //---------------------------------------------------------------------
22 | protected internal override void Init(in DataPoint incoming) => throw new NotSupportedException();
23 | protected internal override ref (bool Archive, bool MaxDelta) IsPointToArchive(in DataPoint incoming, in DataPoint lastArchived) => throw new NotSupportedException();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/ICompression.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace gfoidl.DataCompression
7 | {
8 | ///
9 | /// Defines the interface for the compression algorithms.
10 | ///
11 | public interface ICompression
12 | {
13 | ///
14 | /// When set to true the incoming value is archived in addition
15 | /// to the last snapshot.
16 | ///
17 | ///
18 | /// For instance in the the last snapshot
19 | /// is archived, as well as the current incoming value, therefore this property
20 | /// is set to true.
21 | /// In the only the last snapshot is
22 | /// archived, so this property is set to false.
23 | ///
24 | bool ArchiveIncoming { get; }
25 | //-------------------------------------------------------------------------
26 | ///
27 | /// Length of x before for sure a value gets recorded.
28 | ///
29 | ///
30 | /// Cf. ExMax in documentation.
31 | /// When specified as the
32 | /// are used.
33 | ///
34 | /// When value is null, no value -- except the first and last -- are
35 | /// guaranteed to be recorded.
36 | ///
37 | ///
38 | double? MaxDeltaX { get; }
39 | //---------------------------------------------------------------------
40 | ///
41 | /// Length of x/time within no value gets recorded (after the last archived value)
42 | ///
43 | double? MinDeltaX { get; }
44 | //---------------------------------------------------------------------
45 | ///
46 | /// Performs the compression / filtering of the input data.
47 | ///
48 | /// Input data
49 | /// The compressed / filtered data.
50 | ///
51 | /// is null.
52 | ///
53 | DataPointIterator Process(IEnumerable data);
54 | //---------------------------------------------------------------------
55 | #if NETSTANDARD2_1
56 | ///
57 | /// Performs the compression / filtering of the input data.
58 | ///
59 | /// Input data
60 | /// The compressed / filtered data.
61 | ///
62 | /// is null.
63 | ///
64 | DataPointIterator ProcessAsync(IAsyncEnumerable data);
65 | #endif
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/ThrowHelper.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Diagnostics;
5 | using System.Diagnostics.CodeAnalysis;
6 |
7 | namespace gfoidl.DataCompression
8 | {
9 | internal static class ThrowHelper
10 | {
11 | [DoesNotReturn] public static void ThrowArgumentNull(ExceptionArgument argument) => throw new ArgumentNullException(GetArgumentName(argument));
12 | [DoesNotReturn] public static void ThrowArgumentOutOfRange(ExceptionArgument argument) => throw new ArgumentOutOfRangeException(GetArgumentName(argument));
13 | [DoesNotReturn] public static void ThrowArgument(ExceptionResource resource) => throw new ArgumentException(GetResourceText(resource));
14 | [DoesNotReturn] public static void ThrowNotSupported() => throw new NotSupportedException();
15 | [DoesNotReturn] public static void ThrowIfDisposed(ExceptionArgument argument) => throw new ObjectDisposedException(argument.ToString());
16 | [DoesNotReturn] public static void ThrowInvalidOperation(ExceptionResource resource) => throw new InvalidOperationException(GetResourceText(resource));
17 | //---------------------------------------------------------------------
18 | private static string GetArgumentName(ExceptionArgument argument)
19 | {
20 | Debug.Assert(
21 | Enum.IsDefined(typeof(ExceptionArgument), argument),
22 | "The enum value is not defined, please check the 'ExceptionArgument' enum.");
23 |
24 | return argument.ToString();
25 | }
26 | //---------------------------------------------------------------------
27 | private static string GetResourceName(ExceptionResource resource)
28 | {
29 | Debug.Assert(
30 | Enum.IsDefined(typeof(ExceptionResource), resource),
31 | "The enum value is not defined, please check the 'ExceptionResource' enum.");
32 |
33 | return resource.ToString();
34 | }
35 | //---------------------------------------------------------------------
36 | private static string GetResourceText(ExceptionResource resource)
37 | {
38 | string? tmp = Strings.ResourceManager.GetString(GetResourceName(resource), Strings.Culture);
39 |
40 | Debug.Assert(tmp != null);
41 | return tmp!;
42 | }
43 | //---------------------------------------------------------------------
44 | public enum ExceptionArgument : byte
45 | {
46 | algorithm,
47 | data,
48 | iterator
49 | }
50 | //---------------------------------------------------------------------
51 | public enum ExceptionResource : byte
52 | {
53 | GetEnumerator_must_be_called_first,
54 | Gradient_A_eq_B,
55 | Should_not_happen
56 | }
57 | }
58 | }
59 | //-----------------------------------------------------------------------------
60 | #if !NETSTANDARD2_1
61 | namespace System.Diagnostics.CodeAnalysis
62 | {
63 | [AttributeUsage(AttributeTargets.Method, Inherited = false)]
64 | internal sealed class DoesNotReturnAttribute : Attribute
65 | { }
66 | }
67 | #endif
68 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Wrappers/ArrayWrapper.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 |
7 | namespace gfoidl.DataCompression.Wrappers
8 | {
9 | #pragma warning disable CS1591
10 | public readonly struct ArrayWrapper : IList
11 | {
12 | private readonly T[] _array;
13 | //---------------------------------------------------------------------
14 | public ArrayWrapper(T[]? array) => _array = array ?? throw new ArgumentNullException(nameof(array));
15 | //---------------------------------------------------------------------
16 | public T this[int index]
17 | {
18 | get => _array[index];
19 | set => _array[index] = value;
20 | }
21 | //---------------------------------------------------------------------
22 | public int Count => _array.Length;
23 | //---------------------------------------------------------------------
24 | public bool IsReadOnly => throw new NotSupportedException();
25 | public void Add(T item) => throw new NotSupportedException();
26 | public void Clear() => throw new NotSupportedException();
27 | public bool Contains(T item) => throw new NotSupportedException();
28 | public void CopyTo(T[] array, int arrayIndex) => throw new NotSupportedException();
29 | public IEnumerator GetEnumerator() => throw new NotSupportedException();
30 | public int IndexOf(T item) => throw new NotSupportedException();
31 | public void Insert(int index, T item) => throw new NotSupportedException();
32 | public bool Remove(T item) => throw new NotSupportedException();
33 | public void RemoveAt(int index) => throw new NotSupportedException();
34 | IEnumerator IEnumerable.GetEnumerator() => throw new NotSupportedException();
35 | }
36 | #pragma warning restore CS1591
37 | }
38 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/Wrappers/ListWrapper.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 |
7 | namespace gfoidl.DataCompression.Wrappers
8 | {
9 | #pragma warning disable CS1591
10 | public readonly struct ListWrapper : IList
11 | {
12 | private readonly List _list;
13 | //---------------------------------------------------------------------
14 | public ListWrapper(List? list) => _list = list ?? throw new ArgumentNullException(nameof(list));
15 | //---------------------------------------------------------------------
16 | public T this[int index]
17 | {
18 | get => _list[index];
19 | set => _list[index] = value;
20 | }
21 | //---------------------------------------------------------------------
22 | public int Count => _list.Count;
23 | //---------------------------------------------------------------------
24 | public bool IsReadOnly => throw new NotSupportedException();
25 | public void Add(T item) => throw new NotSupportedException();
26 | public void Clear() => throw new NotSupportedException();
27 | public bool Contains(T item) => throw new NotSupportedException();
28 | public void CopyTo(T[] array, int arrayIndex) => throw new NotSupportedException();
29 | public IEnumerator GetEnumerator() => throw new NotSupportedException();
30 | public int IndexOf(T item) => throw new NotSupportedException();
31 | public void Insert(int index, T item) => throw new NotSupportedException();
32 | public bool Remove(T item) => throw new NotSupportedException();
33 | public void RemoveAt(int index) => throw new NotSupportedException();
34 | IEnumerator IEnumerable.GetEnumerator() => throw new NotSupportedException();
35 | }
36 | #pragma warning restore CS1591
37 | }
38 |
--------------------------------------------------------------------------------
/source/gfoidl.DataCompression/gfoidl.DataCompression.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1;netstandard2.0
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CS8600;CS8602;CS8604
10 |
11 |
12 |
13 | data compression;swinging-door-algorithm;dead-band-filtering;swinging-door;swinging
14 | Provides several data-compression algorithms:
15 |
16 | * error band elimination
17 | * swinging door algorithm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | True
33 | True
34 | Strings.resx
35 |
36 |
37 |
38 |
39 |
40 | ResXFileCodeGenerator
41 | Strings.Designer.cs
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/tests/.editorconfig:
--------------------------------------------------------------------------------
1 | root = false
2 |
3 | # C# files
4 | [*.cs]
5 |
6 | # NUnit2005: Consider using Assert.That(actual, Is.EqualTo(expected)) instead of Assert.AreEqual(expected, actual).
7 | dotnet_diagnostic.NUnit2005.severity = silent
8 |
9 | # NUnit2015: Consider using Assert.That(actual, Is.SameAs(expected)) instead of Assert.AreSame(expected, actual).
10 | dotnet_diagnostic.NUnit2015.severity = silent
11 |
12 | # NUnit2027: Consider using Assert.That(actual, Is.GreaterThan(expected)) instead of Assert.Greater(actual, expected).
13 | dotnet_diagnostic.NUnit2027.severity = silent
14 |
15 | # RCS1090: Call 'ConfigureAwait(false)'.
16 | dotnet_diagnostic.RCS1090.severity = silent
17 |
18 | # NUnit2003: Consider using Assert.That(expr, Is.True) instead of Assert.IsTrue(expr).
19 | dotnet_diagnostic.NUnit2003.severity = silent
20 |
21 | # NUnit2002: Consider using Assert.That(expr, Is.False) instead of Assert.IsFalse(expr).
22 | dotnet_diagnostic.NUnit2002.severity = silent
23 |
24 | # NUnit2038: Consider using Assert.That(actual, Is.InstanceOf(expected)) instead of Assert.IsInstanceOf(expected, actual)
25 | dotnet_diagnostic.NUnit2038.severity = silent
26 |
27 | # NUnit2017: Consider using Assert.That(expr, Is.Null) instead of Assert.IsNull(expr)
28 | dotnet_diagnostic.NUnit2017.severity = silent
29 |
30 | # NUnit2031: Consider using Assert.That(actual, Is.Not.SameAs(expected)) instead of Assert.AreNotSame(expected, actual)
31 | dotnet_diagnostic.NUnit2031.severity = none
32 |
--------------------------------------------------------------------------------
/tests/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | $(StandardTfm)
7 | $(StandardTestTfms);net48
8 |
9 |
10 |
11 | false
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | all
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 |
22 |
23 | all
24 | runtime; build; native; contentfiles; analyzers; buildtransitive
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Builders/ArrayBuilderTests/Add.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using gfoidl.DataCompression.Builders;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.Builders.ArrayBuilderTests
8 | {
9 | [TestFixture]
10 | public class Add
11 | {
12 | [Test, TestCaseSource(nameof(Add_items_ToArray___correct_result_TestCases))]
13 | public void Add_items_ToArray___correct_result(int size)
14 | {
15 | var expected = new int[size];
16 | var sut = new ArrayBuilder(true);
17 |
18 | for (int i = 0; i < size; ++i)
19 | {
20 | expected[i] = i;
21 | sut.Add(i);
22 | }
23 |
24 | int[] actual = sut.ToArray();
25 |
26 | CollectionAssert.AreEqual(expected, actual);
27 | }
28 | //---------------------------------------------------------------------
29 | private static IEnumerable Add_items_ToArray___correct_result_TestCases()
30 | {
31 | yield return new TestCaseData(0);
32 | yield return new TestCaseData(1);
33 | yield return new TestCaseData(2);
34 | yield return new TestCaseData(4);
35 | yield return new TestCaseData(5); // StartCapacity + 1
36 | yield return new TestCaseData(8);
37 | yield return new TestCaseData(9); // ResizeThreshold + 1
38 | yield return new TestCaseData(16);
39 | yield return new TestCaseData(100);
40 | yield return new TestCaseData(1_000);
41 | yield return new TestCaseData(1_001);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Builders/ArrayBuilderTests/AddRange.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using gfoidl.DataCompression.Builders;
6 | using NUnit.Framework;
7 |
8 | namespace gfoidl.DataCompression.Tests.Builders.ArrayBuilderTests
9 | {
10 | [TestFixture]
11 | public class AddRange
12 | {
13 | [Test]
14 | public void IEnumerable___correct_result()
15 | {
16 | int[] expected = Getvalues().ToArray();
17 | var sut = new ArrayBuilder(true);
18 |
19 | sut.AddRange(Getvalues());
20 |
21 | int[] actual = sut.ToArray();
22 |
23 | CollectionAssert.AreEqual(expected, actual);
24 | }
25 | //---------------------------------------------------------------------
26 | [Test]
27 | public void Array___correct_result()
28 | {
29 | int[] expected = Getvalues().ToArray();
30 | var sut = new ArrayBuilder(true);
31 |
32 | sut.AddRange(expected);
33 |
34 | int[] actual = sut.ToArray();
35 |
36 | CollectionAssert.AreEqual(expected, actual);
37 | }
38 | //---------------------------------------------------------------------
39 | private static IEnumerable Getvalues()
40 | {
41 | yield return 0;
42 | yield return 1;
43 | yield return 2;
44 | yield return 4;
45 | yield return 8;
46 | yield return 16;
47 | yield return 100;
48 | yield return 1_000;
49 | yield return 1_001;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/DeadBandCompressionTests/Base.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 |
5 | #if NETCOREAPP
6 | using System.Runtime.CompilerServices;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | #endif
10 |
11 | namespace gfoidl.DataCompression.Tests.Compression.DeadBandCompressionTests
12 | {
13 | public abstract class Base : Compression.Base
14 | {
15 | protected static IEnumerable RawDataForTrend() => s_ser.Read("data/dead-band/trend_raw.csv");
16 | protected static IEnumerable ExpectedForTrend() => s_ser.Read("data/dead-band/trend_compressed.csv");
17 | protected static IEnumerable RawDataForMaxDelta() => s_ser.Read("data/dead-band/maxDelta_raw.csv");
18 | protected static IEnumerable ExpectedForMaxDelta() => s_ser.Read("data/dead-band/maxDelta_compressed.csv");
19 | //---------------------------------------------------------------------
20 | #if NETCOREAPP
21 | protected static async IAsyncEnumerable RawDataForTrendAsync([EnumeratorCancellation] CancellationToken ct = default)
22 | {
23 | foreach (DataPoint dp in RawDataForTrend())
24 | {
25 | ct.ThrowIfCancellationRequested();
26 | await Task.Yield();
27 | yield return dp;
28 | }
29 | }
30 | //---------------------------------------------------------------------
31 | protected static async IAsyncEnumerable RawDataForMaxDeltaAsync([EnumeratorCancellation] CancellationToken ct = default)
32 | {
33 | foreach (DataPoint dp in RawDataForMaxDelta())
34 | {
35 | ct.ThrowIfCancellationRequested();
36 | await Task.Yield();
37 | yield return dp;
38 | }
39 | }
40 | #endif
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/DeadBandCompressionTests/Clone.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Linq;
4 | using NUnit.Framework;
5 |
6 | namespace gfoidl.DataCompression.Tests.Compression.DeadBandCompressionTests
7 | {
8 | public class Clone : Base
9 | {
10 | [Test]
11 | public void Cloning_iterates_over_fresh_set()
12 | {
13 | var sut = new DeadBandCompression(0.1);
14 | var data = KnownSequence().ToArray().Select(dp => dp);
15 | var expected = KnownSequenceExpected(swingingDoor: false).ToArray();
16 | var filter = sut.Process(data);
17 |
18 | var iterator = filter.GetEnumerator();
19 | iterator.MoveNext();
20 |
21 | iterator = filter.Clone().GetEnumerator();
22 |
23 | Assert.Multiple(() =>
24 | {
25 | int step = 0;
26 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
27 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
28 | step++;
29 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
30 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
31 | step++;
32 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
33 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
34 | step++;
35 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
36 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
37 | step++;
38 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
39 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
40 | step++;
41 | Assert.IsFalse(iterator.MoveNext(), $"MoveNext step: {step++}");
42 | });
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/DeadBandCompressionTests/MoveNextAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using NUnit.Framework;
7 |
8 | namespace gfoidl.DataCompression.Tests.Compression.DeadBandCompressionTests
9 | {
10 | public class MoveNextAsync : Base
11 | {
12 | [Test]
13 | public async Task Empty_IAsyncEnumerable___empty_result()
14 | {
15 | var sut = new DeadBandCompression(0.1);
16 | var data = EmptyAsync();
17 | var iterator = sut.ProcessAsync(data).GetAsyncEnumerator();
18 |
19 | Assert.IsFalse(await iterator.MoveNextAsync());
20 | }
21 | //---------------------------------------------------------------------
22 | [Test]
23 | public async Task Empty_IAsyncEnumerable_foreach___empty_result()
24 | {
25 | var sut = new DeadBandCompression(0.1);
26 | var data = EmptyAsync();
27 |
28 | int count = 0;
29 | await foreach (DataPoint db in sut.ProcessAsync(data))
30 | {
31 | count++;
32 | }
33 |
34 | Assert.AreEqual(0, count);
35 | }
36 | //---------------------------------------------------------------------
37 | [Test]
38 | public void Known_sequence___correct_result()
39 | {
40 | var sut = new DeadBandCompression(0.1);
41 | var data = KnownSequenceAsync();
42 | var iterator = sut.ProcessAsync(data).GetAsyncEnumerator();
43 | var expected = KnownSequenceExpected(swingingDoor: false).ToArray();
44 |
45 | Assert.Multiple(async () =>
46 | {
47 | await iterator.MoveNextAsync();
48 | Assert.AreEqual(expected[0], iterator.Current);
49 | await iterator.MoveNextAsync();
50 | Assert.AreEqual(expected[1], iterator.Current);
51 | await iterator.MoveNextAsync();
52 | Assert.AreEqual(expected[2], iterator.Current);
53 | await iterator.MoveNextAsync();
54 | Assert.AreEqual(expected[3], iterator.Current);
55 | });
56 | }
57 | //---------------------------------------------------------------------
58 | [Test]
59 | public async Task Known_sequence_foreach___correct_result()
60 | {
61 | var sut = new DeadBandCompression(0.1);
62 | var data = KnownSequenceAsync();
63 | var result = sut.ProcessAsync(data);
64 | var expected = KnownSequenceExpected(swingingDoor: false).ToArray();
65 | var actual = new List();
66 |
67 | await foreach (DataPoint dp in result)
68 | actual.Add(dp);
69 |
70 | CollectionAssert.AreEqual(expected, actual);
71 | }
72 | //---------------------------------------------------------------------
73 | [Test]
74 | public async Task InstrumentPrecision_0___input_echoed()
75 | {
76 | var sut = new DeadBandCompression(0);
77 | var data = KnownSequenceAsync();
78 | var result = sut.ProcessAsync(data);
79 | var expected = KnownSequence().ToArray();
80 | var actual = new List();
81 |
82 | await foreach (DataPoint dp in result)
83 | actual.Add(dp);
84 |
85 | CollectionAssert.AreEqual(expected, actual);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/DeadBandCompressionTests/ProcessAsyncCore.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using NUnit.Framework;
9 |
10 | namespace gfoidl.DataCompression.Tests.Compression.DeadBandCompressionTests
11 | {
12 | public class ProcessAsyncCore : Base
13 | {
14 | [Test]
15 | public async Task Data_given_as_IAsyncEnumerable___OK()
16 | {
17 | var sut = new DeadBandCompression(0.1);
18 | var data = RawDataForTrendAsync();
19 | var expected = ExpectedForTrend().ToList();
20 |
21 | var actual = new List();
22 | await foreach (DataPoint dp in sut.ProcessAsync(data))
23 | actual.Add(dp);
24 |
25 | Print(expected, "expected");
26 | Print(actual , "actual");
27 | CollectionAssert.AreEqual(expected, actual);
28 | }
29 | //---------------------------------------------------------------------
30 | [Test]
31 | public void Cancellation_after_two_items___OK()
32 | {
33 | var sut = new DeadBandCompression(0.1);
34 | var data = KnownSequenceAsync();
35 | var expected = KnownSequence().Take(2).ToList();
36 | var cts = new CancellationTokenSource();
37 |
38 | var actual = new List();
39 | int idx = 0;
40 |
41 | Assert.ThrowsAsync(async () =>
42 | {
43 | await foreach (DataPoint dp in sut.ProcessAsync(data).WithCancellation(cts.Token))
44 | {
45 | actual.Add(dp);
46 | idx++;
47 |
48 | if (idx == 2) cts.Cancel();
49 | }
50 | });
51 |
52 | CollectionAssert.AreEqual(actual, expected);
53 | }
54 | //---------------------------------------------------------------------
55 | [Test]
56 | public async Task Data_IAsyncEnumerable_with_maxDeltaX___OK()
57 | {
58 | var sut = new DeadBandCompression(0.1, 4d);
59 | var data = RawDataForMaxDeltaAsync();
60 | var expected = ExpectedForMaxDelta().ToList();
61 |
62 | var actual = new List();
63 | await foreach (DataPoint dp in sut.ProcessAsync(data))
64 | actual.Add(dp);
65 |
66 | CollectionAssert.AreEqual(expected, actual);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/DeadBandCompressionTests/ToArrayAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using NUnit.Framework;
9 |
10 | namespace gfoidl.DataCompression.Tests.Compression.DeadBandCompressionTests
11 | {
12 | public class ToArrayAsync : Base
13 | {
14 | [Test]
15 | public async Task Empty_IAsyncEnumerable___empty_result()
16 | {
17 | var sut = new DeadBandCompression(0.1);
18 | var data = EmptyAsync();
19 |
20 | var actual = sut.ProcessAsync(data);
21 |
22 | Assert.AreEqual(0, (await actual.ToListAsync()).Count);
23 | }
24 | //---------------------------------------------------------------------
25 | [Test]
26 | public async Task Data_given_as_IAsyncEnumerable___OK()
27 | {
28 | var sut = new DeadBandCompression(0.1);
29 | var data = RawDataForTrendAsync();
30 | var expected = ExpectedForTrend().ToList();
31 |
32 | var actual = await sut.ProcessAsync(data).ToArrayAsync();
33 |
34 | CollectionAssert.AreEqual(expected, actual);
35 | }
36 | //---------------------------------------------------------------------
37 | [Test]
38 | public async Task Data_IAsyncEnumerable_with_maxDeltaX___OK()
39 | {
40 | var sut = new DeadBandCompression(0.1, 4d);
41 | var data = RawDataForMaxDeltaAsync();
42 | var expected = ExpectedForMaxDelta().ToList();
43 |
44 | var actual = await sut.ProcessAsync(data).ToArrayAsync();
45 |
46 | CollectionAssert.AreEqual(expected, actual);
47 | }
48 | //---------------------------------------------------------------------
49 | [Test]
50 | public async Task IEnumerable_iterated_and_ToArray___OK()
51 | {
52 | var sut = new DeadBandCompression(0.1);
53 | var data = RawDataForTrendAsync();
54 | var expected = ExpectedForTrend().ToList();
55 |
56 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
57 | var enumerator = dataPointIterator.GetAsyncEnumerator();
58 |
59 | await enumerator.MoveNextAsync();
60 | await enumerator.MoveNextAsync();
61 | var actual = await dataPointIterator.ToArrayAsync();
62 |
63 | CollectionAssert.AreEqual(expected, actual);
64 | }
65 | //---------------------------------------------------------------------
66 | [Test]
67 | public async Task Cancellation___OK()
68 | {
69 | var sut = new DeadBandCompression(0.1);
70 | var data = RawDataForTrendAsync();
71 | var expected = ExpectedForTrend().Take(2).ToList();
72 |
73 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
74 | var cts = new CancellationTokenSource();
75 | var enumerator = dataPointIterator.GetAsyncEnumerator(cts.Token);
76 |
77 | var actual = new List();
78 | await enumerator.MoveNextAsync();
79 | actual.Add(enumerator.Current);
80 | await enumerator.MoveNextAsync();
81 | actual.Add(enumerator.Current);
82 | cts.Cancel();
83 |
84 | DataPoint[] res = null;
85 | Assert.ThrowsAsync(async () => res = await dataPointIterator.ToArrayAsync(cts.Token));
86 |
87 | CollectionAssert.AreEqual(expected, actual);
88 | Assert.IsNull(res);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/DeadBandCompressionTests/ToListAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using NUnit.Framework;
9 |
10 | namespace gfoidl.DataCompression.Tests.Compression.DeadBandCompressionTests
11 | {
12 | public class ToListAsync : Base
13 | {
14 | [Test]
15 | public async Task Data_given_as_IAsyncEnumerable___OK()
16 | {
17 | var sut = new DeadBandCompression(0.1);
18 | var data = RawDataForTrendAsync();
19 | var expected = ExpectedForTrend().ToList();
20 |
21 | var actual = await sut.ProcessAsync(data).ToListAsync();
22 |
23 | CollectionAssert.AreEqual(expected, actual);
24 | }
25 | //---------------------------------------------------------------------
26 | [Test]
27 | public async Task Data_IAsyncEnumerable_with_maxDeltaX___OK()
28 | {
29 | var sut = new DeadBandCompression(0.1, 4d);
30 | var data = RawDataForMaxDeltaAsync();
31 | var expected = ExpectedForMaxDelta().ToList();
32 |
33 | var actual = await sut.ProcessAsync(data).ToListAsync();
34 |
35 | CollectionAssert.AreEqual(expected, actual);
36 | }
37 | //---------------------------------------------------------------------
38 | [Test]
39 | public async Task IEnumerable_iterated_and_ToList___OK()
40 | {
41 | var sut = new DeadBandCompression(0.1);
42 | var data = RawDataForTrendAsync();
43 | var expected = ExpectedForTrend().ToList();
44 |
45 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
46 | var enumerator = dataPointIterator.GetAsyncEnumerator();
47 |
48 | await enumerator.MoveNextAsync();
49 | await enumerator.MoveNextAsync();
50 | var actual = await dataPointIterator.ToListAsync();
51 |
52 | CollectionAssert.AreEqual(expected, actual);
53 | }
54 | //---------------------------------------------------------------------
55 | [Test]
56 | public async Task Cancellation___OK()
57 | {
58 | var sut = new DeadBandCompression(0.1);
59 | var data = RawDataForTrendAsync();
60 | var expected = ExpectedForTrend().Take(2).ToList();
61 |
62 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
63 | var cts = new CancellationTokenSource();
64 | var enumerator = dataPointIterator.GetAsyncEnumerator(cts.Token);
65 |
66 | var actual = new List();
67 | await enumerator.MoveNextAsync();
68 | actual.Add(enumerator.Current);
69 | await enumerator.MoveNextAsync();
70 | actual.Add(enumerator.Current);
71 | cts.Cancel();
72 |
73 | List res = null;
74 | Assert.ThrowsAsync(async () => res = await dataPointIterator.ToListAsync(cts.Token));
75 |
76 | CollectionAssert.AreEqual(expected, actual);
77 | Assert.IsNull(res);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/DisposeTests.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.Compression;
8 |
9 | [TestFixture(typeof(DeadBandCompression))]
10 | [TestFixture(typeof(NoCompression))]
11 | [TestFixture(typeof(SwingingDoorCompression))]
12 | public class DisposeTests : Base where TCompression : ICompression, new()
13 | {
14 | private ICompression _sut = new TCompression();
15 | //-------------------------------------------------------------------------
16 | [Test]
17 | public void Enumerable_Dispose_after_foreach___OK()
18 | {
19 | using DataPointIterator filtered = _sut.Process(KnownSequence().Take(1));
20 | _ = Consume(filtered);
21 | }
22 | //-------------------------------------------------------------------------
23 | [Test]
24 | public void Array_Dispose_after_foreach___OK()
25 | {
26 | using DataPointIterator filtered = _sut.Process(KnownSequence().Take(1).ToArray());
27 | _ = Consume(filtered);
28 | }
29 | //-------------------------------------------------------------------------
30 | [Test]
31 | public void List_Dispose_after_foreach___OK()
32 | {
33 | using DataPointIterator filtered = _sut.Process(KnownSequence().Take(1).ToList());
34 | _ = Consume(filtered);
35 | }
36 | //-------------------------------------------------------------------------
37 | private static double Consume(DataPointIterator dataPointIterator)
38 | {
39 | double sum = 0;
40 |
41 | foreach (DataPoint dataPoint in dataPointIterator)
42 | {
43 | sum += dataPoint.Y;
44 | }
45 |
46 | return sum;
47 | }
48 | //-------------------------------------------------------------------------
49 | #if NETCOREAPP
50 | [Test]
51 | public async Task AsyncEnumerable_Dispose_after_foreach___OK()
52 | {
53 | using DataPointIterator filtered = _sut.ProcessAsync(KnownSequenceAsync());
54 | _ = await ConsumeAsync(filtered);
55 | }
56 | //-------------------------------------------------------------------------
57 | private static async ValueTask ConsumeAsync(DataPointIterator dataPointIterator)
58 | {
59 | double sum = 0;
60 |
61 | await foreach (DataPoint dataPoint in dataPointIterator)
62 | {
63 | sum += dataPoint.Y;
64 | }
65 |
66 | return sum;
67 | }
68 | #endif
69 | }
70 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/NoCompressionTests/Base.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 |
5 | #if NETCOREAPP
6 | using System.Runtime.CompilerServices;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | #endif
10 |
11 | namespace gfoidl.DataCompression.Tests.Compression.NoCompressionTests
12 | {
13 | public abstract class Base : Compression.Base
14 | {
15 | protected static IEnumerable RawDataForTrend() => s_ser.Read("data/dead-band/trend_raw.csv");
16 | protected static IEnumerable RawDataForMaxDelta() => s_ser.Read("data/dead-band/maxDelta_raw.csv");
17 | //---------------------------------------------------------------------
18 | #if NETCOREAPP
19 | protected static async IAsyncEnumerable RawDataForTrendAsync([EnumeratorCancellation] CancellationToken ct = default)
20 | {
21 | foreach (DataPoint dp in RawDataForTrend())
22 | {
23 | ct.ThrowIfCancellationRequested();
24 | await Task.Yield();
25 | yield return dp;
26 | }
27 | }
28 | //---------------------------------------------------------------------
29 | protected static async IAsyncEnumerable RawDataForMaxDeltaAsync([EnumeratorCancellation] CancellationToken ct = default)
30 | {
31 | foreach (DataPoint dp in RawDataForMaxDelta())
32 | {
33 | ct.ThrowIfCancellationRequested();
34 | await Task.Yield();
35 | yield return dp;
36 | }
37 | }
38 | #endif
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/NoCompressionTests/Clone.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Linq;
4 | using NUnit.Framework;
5 |
6 | namespace gfoidl.DataCompression.Tests.Compression.NoCompressionTests
7 | {
8 | public class Clone : Base
9 | {
10 | [Test]
11 | public void Cloning_iterates_over_fresh_set()
12 | {
13 | var sut = new NoCompression();
14 | var data = KnownSequence().ToArray().Select(dp => dp);
15 | var expected = KnownSequence().ToArray();
16 | var filter = sut.Process(data);
17 |
18 | var iterator = filter.GetEnumerator();
19 | iterator.MoveNext();
20 |
21 | iterator = filter.Clone().GetEnumerator();
22 |
23 | Assert.Multiple(() =>
24 | {
25 | int step = 0;
26 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
27 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
28 | step++;
29 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
30 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
31 | step++;
32 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
33 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
34 | step++;
35 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
36 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
37 | step++;
38 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
39 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
40 | step++;
41 | Assert.IsFalse(iterator.MoveNext(), $"MoveNext step: {step++}");
42 | });
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/NoCompressionTests/MoveNextAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using NUnit.Framework;
7 |
8 | namespace gfoidl.DataCompression.Tests.Compression.NoCompressionTests
9 | {
10 | public class MoveNextAsync : Base
11 | {
12 | [Test]
13 | public async Task Empty_IAsyncEnumerable___empty_result()
14 | {
15 | var sut = new NoCompression();
16 | var data = EmptyAsync();
17 | var iterator = sut.ProcessAsync(data).GetAsyncEnumerator();
18 |
19 | Assert.IsFalse(await iterator.MoveNextAsync());
20 | }
21 | //---------------------------------------------------------------------
22 | [Test]
23 | public async Task Empty_IAsyncEnumerable_foreach___empty_result()
24 | {
25 | var sut = new NoCompression();
26 | var data = EmptyAsync();
27 |
28 | int count = 0;
29 | await foreach (DataPoint db in sut.ProcessAsync(data))
30 | {
31 | count++;
32 | }
33 |
34 | Assert.AreEqual(0, count);
35 | }
36 | //---------------------------------------------------------------------
37 | [Test]
38 | public async Task Known_sequence___correct_result()
39 | {
40 | var sut = new NoCompression();
41 | var data = KnownSequenceAsync();
42 | var iterator = sut.ProcessAsync(data).GetAsyncEnumerator();
43 | var expected = new List();
44 |
45 | await foreach (DataPoint dp in KnownSequenceAsync())
46 | expected.Add(dp);
47 |
48 | Assert.Multiple(async () =>
49 | {
50 | await iterator.MoveNextAsync();
51 | Assert.AreEqual(expected[0], iterator.Current);
52 | await iterator.MoveNextAsync();
53 | Assert.AreEqual(expected[1], iterator.Current);
54 | await iterator.MoveNextAsync();
55 | Assert.AreEqual(expected[2], iterator.Current);
56 | });
57 | }
58 | //---------------------------------------------------------------------
59 | [Test]
60 | public async Task Known_sequence_foreach___correct_result()
61 | {
62 | var sut = new NoCompression();
63 | var data = KnownSequenceAsync();
64 | var result = sut.ProcessAsync(data);
65 | var expected = new List();
66 | var actual = new List();
67 |
68 | await foreach (DataPoint dp in KnownSequenceAsync())
69 | expected.Add(dp);
70 |
71 | await foreach (DataPoint dp in result)
72 | actual.Add(dp);
73 |
74 | CollectionAssert.AreEqual(expected, actual);
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/NoCompressionTests/ProcessAsyncCore.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using NUnit.Framework;
9 |
10 | namespace gfoidl.DataCompression.Tests.Compression.NoCompressionTests
11 | {
12 | public class ProcessAsyncCore : Base
13 | {
14 | [Test]
15 | public async Task Data_given_as_IAsyncEnumerable___OK()
16 | {
17 | var sut = new NoCompression();
18 | var data = RawDataForTrendAsync();
19 | var expected = RawDataForTrend().ToList();
20 |
21 | var actual = new List();
22 | await foreach (DataPoint dp in sut.ProcessAsync(data))
23 | actual.Add(dp);
24 |
25 | CollectionAssert.AreEqual(expected, actual);
26 | }
27 | //---------------------------------------------------------------------
28 | [Test]
29 | public void Cancellation_after_two_items___OK()
30 | {
31 | var sut = new NoCompression();
32 | var data = RawDataForTrendAsync();
33 | var expected = RawDataForTrend().Take(2).ToList();
34 | var cts = new CancellationTokenSource();
35 |
36 | var actual = new List();
37 | int idx = 0;
38 |
39 | Assert.ThrowsAsync(async () =>
40 | {
41 | await foreach (DataPoint dp in sut.ProcessAsync(data).WithCancellation(cts.Token))
42 | {
43 | actual.Add(dp);
44 | idx++;
45 |
46 | if (idx == 2) cts.Cancel();
47 | }
48 | });
49 |
50 | CollectionAssert.AreEqual(actual, expected);
51 | }
52 | //---------------------------------------------------------------------
53 | [Test]
54 | public async Task Data_IAsyncEnumerable_with_maxDeltaX___OK()
55 | {
56 | var sut = new NoCompression();
57 | var data = RawDataForMaxDeltaAsync();
58 | var expected = RawDataForMaxDelta().ToList();
59 |
60 | var actual = new List();
61 | await foreach (DataPoint dp in sut.ProcessAsync(data))
62 | actual.Add(dp);
63 |
64 | CollectionAssert.AreEqual(expected, actual);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/NoCompressionTests/ToArrayAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using NUnit.Framework;
9 |
10 | namespace gfoidl.DataCompression.Tests.Compression.NoCompressionTests
11 | {
12 | public class ToArrayAsync : Base
13 | {
14 | [Test]
15 | public async Task Data_given_as_IAsyncEnumerable___OK()
16 | {
17 | var sut = new NoCompression();
18 | var data = RawDataForTrendAsync();
19 | var expected = RawDataForTrend().ToList();
20 |
21 | var actual = await sut.ProcessAsync(data).ToArrayAsync();
22 |
23 | Print(expected, "expected");
24 | Print(actual , "actual");
25 | CollectionAssert.AreEqual(expected, actual);
26 | }
27 | //---------------------------------------------------------------------
28 | [Test]
29 | public async Task Data_IAsyncEnumerable_with_maxDeltaX___OK()
30 | {
31 | var sut = new NoCompression();
32 | var data = RawDataForMaxDeltaAsync();
33 | var expected = RawDataForMaxDelta().ToList();
34 |
35 | var actual = await sut.ProcessAsync(data).ToArrayAsync();
36 |
37 | Print(expected, "expected");
38 | Print(actual , "actual");
39 | CollectionAssert.AreEqual(expected, actual);
40 | }
41 | //---------------------------------------------------------------------
42 | [Test]
43 | public async Task IAsyncEnumerable_iterated_and_ToArray___OK()
44 | {
45 | var sut = new NoCompression();
46 | var data = RawDataForTrendAsync();
47 | var expected = RawDataForTrend().ToList();
48 |
49 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
50 | var enumerator = dataPointIterator.GetAsyncEnumerator();
51 |
52 | await enumerator.MoveNextAsync();
53 | await enumerator.MoveNextAsync();
54 | var actual = await dataPointIterator.ToArrayAsync();
55 |
56 | Print(expected, "expected");
57 | Print(actual , "actual");
58 | CollectionAssert.AreEqual(expected, actual);
59 | }
60 | //---------------------------------------------------------------------
61 | [Test]
62 | public async Task Cancellation___OK()
63 | {
64 | var sut = new NoCompression();
65 | var data = RawDataForTrendAsync();
66 | var expected = RawDataForTrend().Take(2).ToList();
67 |
68 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
69 | var cts = new CancellationTokenSource();
70 | var enumerator = dataPointIterator.GetAsyncEnumerator(cts.Token);
71 |
72 | var actual = new List();
73 | await enumerator.MoveNextAsync();
74 | actual.Add(enumerator.Current);
75 | await enumerator.MoveNextAsync();
76 | actual.Add(enumerator.Current);
77 | cts.Cancel();
78 |
79 | DataPoint[] res = null;
80 | Assert.ThrowsAsync(async () => res = await dataPointIterator.ToArrayAsync(cts.Token));
81 |
82 | CollectionAssert.AreEqual(expected, actual);
83 | Assert.IsNull(res);
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/NoCompressionTests/ToListAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using NUnit.Framework;
9 |
10 | namespace gfoidl.DataCompression.Tests.Compression.NoCompressionTests
11 | {
12 | public class ToListAsync : Base
13 | {
14 | [Test]
15 | public async Task Data_given_as_IAsyncEnumerable___OK()
16 | {
17 | var sut = new NoCompression();
18 | var data = RawDataForTrendAsync();
19 | var expected = RawDataForTrend().ToList();
20 |
21 | var actual = await sut.ProcessAsync(data).ToListAsync();
22 |
23 | CollectionAssert.AreEqual(expected, actual);
24 | }
25 | //---------------------------------------------------------------------
26 | [Test]
27 | public async Task Data_IAsyncEnumerable_with_maxDeltaX___OK()
28 | {
29 | var sut = new NoCompression();
30 | var data = RawDataForMaxDeltaAsync();
31 | var expected = RawDataForMaxDelta().ToList();
32 |
33 | var actual = await sut.ProcessAsync(data).ToListAsync();
34 |
35 | CollectionAssert.AreEqual(expected, actual);
36 | }
37 | //---------------------------------------------------------------------
38 | [Test]
39 | public async Task IEnumerable_iterated_and_ToList___OK()
40 | {
41 | var sut = new NoCompression();
42 | var data = RawDataForTrendAsync();
43 | var expected = RawDataForTrend().ToList();
44 |
45 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
46 | var enumerator = dataPointIterator.GetAsyncEnumerator();
47 |
48 | await enumerator.MoveNextAsync();
49 | await enumerator.MoveNextAsync();
50 | var actual = await dataPointIterator.ToListAsync();
51 |
52 | CollectionAssert.AreEqual(expected, actual);
53 | }
54 | //---------------------------------------------------------------------
55 | [Test]
56 | public async Task Cancellation___OK()
57 | {
58 | var sut = new NoCompression();
59 | var data = RawDataForTrendAsync();
60 | var expected = RawDataForTrend().Take(2).ToList();
61 |
62 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
63 | var cts = new CancellationTokenSource();
64 | var enumerator = dataPointIterator.GetAsyncEnumerator(cts.Token);
65 |
66 | var actual = new List();
67 | await enumerator.MoveNextAsync();
68 | actual.Add(enumerator.Current);
69 | await enumerator.MoveNextAsync();
70 | actual.Add(enumerator.Current);
71 | cts.Cancel();
72 |
73 | List res = null;
74 | Assert.ThrowsAsync(async () => res = await dataPointIterator.ToListAsync(cts.Token));
75 |
76 | CollectionAssert.AreEqual(expected, actual);
77 | Assert.IsNull(res);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/SwingingDoorCompressionTests/Clone.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Linq;
4 | using NUnit.Framework;
5 |
6 | namespace gfoidl.DataCompression.Tests.Compression.SwingingDoorCompressionTests
7 | {
8 | public class Clone : Base
9 | {
10 | [Test]
11 | public void Cloning_iterates_over_fresh_set()
12 | {
13 | var sut = new SwingingDoorCompression(1);
14 | var data = KnownSequence().ToArray().Select(dp => dp);
15 | var expected = KnownSequenceExpected().ToArray();
16 | var filter = sut.Process(data);
17 |
18 | var iterator = filter.GetEnumerator();
19 | iterator.MoveNext();
20 |
21 | iterator = filter.Clone().GetEnumerator();
22 |
23 | Assert.Multiple(() =>
24 | {
25 | int step = 0;
26 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
27 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
28 | step++;
29 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
30 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
31 | step++;
32 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
33 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
34 | step++;
35 | Assert.IsTrue(iterator.MoveNext(), $"MoveNext step: {step}");
36 | Assert.AreEqual(expected[step], iterator.Current, $"Equal step: {step}");
37 | step++;
38 | Assert.IsFalse(iterator.MoveNext(), $"MoveNext step: {step++}");
39 | });
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/SwingingDoorCompressionTests/MoveNextAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using NUnit.Framework;
7 |
8 | namespace gfoidl.DataCompression.Tests.Compression.SwingingDoorCompressionTests
9 | {
10 | public class MoveNextAsync : Base
11 | {
12 | [Test]
13 | public async Task Empty_IAsyncEnumerable___empty_result()
14 | {
15 | var sut = new SwingingDoorCompression(1);
16 | var data = EmptyAsync();
17 | var iterator = sut.ProcessAsync(data).GetAsyncEnumerator();
18 |
19 | Assert.IsFalse(await iterator.MoveNextAsync());
20 | }
21 | //---------------------------------------------------------------------
22 | [Test]
23 | public async Task Empty_IAsyncEnumerable_foreach___empty_result()
24 | {
25 | var sut = new SwingingDoorCompression(1);
26 | var data = EmptyAsync();
27 |
28 | int count = 0;
29 | await foreach (DataPoint db in sut.ProcessAsync(data))
30 | {
31 | count++;
32 | }
33 |
34 | Assert.AreEqual(0, count);
35 | }
36 | //---------------------------------------------------------------------
37 | [Test]
38 | public void Known_sequence___correct_result()
39 | {
40 | var sut = new SwingingDoorCompression(1);
41 | var data = KnownSequenceAsync();
42 | var iterator = sut.ProcessAsync(data).GetAsyncEnumerator();
43 | var expected = KnownSequenceExpected().ToArray();
44 |
45 | Assert.Multiple(async () =>
46 | {
47 | await iterator.MoveNextAsync();
48 | Assert.AreEqual(expected[0], iterator.Current);
49 | await iterator.MoveNextAsync();
50 | Assert.AreEqual(expected[1], iterator.Current);
51 | await iterator.MoveNextAsync();
52 | Assert.AreEqual(expected[2], iterator.Current);
53 | await iterator.MoveNextAsync();
54 | Assert.AreEqual(expected[3], iterator.Current);
55 | });
56 | }
57 | //---------------------------------------------------------------------
58 | [Test]
59 | public async Task Known_sequence_foreach___correct_result()
60 | {
61 | var sut = new SwingingDoorCompression(1);
62 | var data = KnownSequenceAsync();
63 | var result = sut.ProcessAsync(data);
64 | var expected = KnownSequenceExpected().ToArray();
65 | var actual = new List();
66 |
67 | await foreach (DataPoint dp in result)
68 | actual.Add(dp);
69 |
70 | CollectionAssert.AreEqual(expected, actual);
71 | }
72 | //---------------------------------------------------------------------
73 | [Test]
74 | public async Task CompressionDeviation_0___input_echoed()
75 | {
76 | var sut = new SwingingDoorCompression(0);
77 | var data = KnownSequenceAsync();
78 | var result = sut.ProcessAsync(data);
79 | var expected = KnownSequence().ToArray();
80 | var actual = new List();
81 |
82 | await foreach (DataPoint dp in result)
83 | actual.Add(dp);
84 |
85 | CollectionAssert.AreEqual(expected, actual);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/SwingingDoorCompressionTests/ToArrayAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using gfoidl.DataCompression.Wrappers;
9 | using NUnit.Framework;
10 |
11 | namespace gfoidl.DataCompression.Tests.Compression.SwingingDoorCompressionTests
12 | {
13 | public class ToArrayAsync : Base
14 | {
15 | [Test]
16 | public async Task Empty_IAsyncEnumerable___empty_result()
17 | {
18 | var sut = new SwingingDoorCompression(1d);
19 | var data = EmptyAsync();
20 |
21 | var actual = sut.ProcessAsync(data);
22 |
23 | Assert.AreEqual(0, (await actual.ToListAsync()).Count);
24 | }
25 | //---------------------------------------------------------------------
26 | [Test, TestCaseSource(typeof(Base), nameof(Base.IAsyncEnumerableTestCases))]
27 | public async Task Data_given_as_IAsyncEnumerable___OK(double compressionDeviation, IAsyncEnumerable rawData, IEnumerable expectedData)
28 | {
29 | var sut = new SwingingDoorCompression(compressionDeviation);
30 | var data = rawData;
31 | var expected = expectedData.ToList();
32 |
33 | var actual = await sut.ProcessAsync(data).ToArrayAsync();
34 |
35 | CollectionAssert.AreEqual(expected, actual);
36 | }
37 | //---------------------------------------------------------------------
38 | [Test]
39 | public async Task Data_IAsyncEnumerable_with_maxDeltaX___OK()
40 | {
41 | var sut = new SwingingDoorCompression(1d, 6d);
42 | var data = RawDataAsync(RawDataForMaxDelta());
43 | var expected = ExpectedForMaxDelta().ToList();
44 |
45 | var actual = await sut.ProcessAsync(data).ToArrayAsync();
46 |
47 | CollectionAssert.AreEqual(expected, actual);
48 | }
49 | //---------------------------------------------------------------------
50 | [Test, TestCaseSource(typeof(Base), nameof(Base.IAsyncEnumerableTestCases))]
51 | public async Task IEnumerable_iterated_and_ToArray___OK(double compressionDeviation, IAsyncEnumerable rawData, IEnumerable expectedData)
52 | {
53 | var sut = new SwingingDoorCompression(compressionDeviation);
54 | var data = rawData;
55 | var expected = expectedData.ToList();
56 |
57 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
58 | var enumerator = dataPointIterator.GetAsyncEnumerator();
59 |
60 | await enumerator.MoveNextAsync();
61 | await enumerator.MoveNextAsync();
62 | var actual = await dataPointIterator.ToArrayAsync();
63 |
64 | CollectionAssert.AreEqual(expected, actual);
65 | }
66 | //---------------------------------------------------------------------
67 | [Test]
68 | public async Task Cancellation___OK()
69 | {
70 | var sut = new SwingingDoorCompression(1d);
71 | var data = RawDataAsync(RawDataForTrend());
72 | var expected = ExpectedForTrend().Take(2).ToList();
73 |
74 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
75 | var cts = new CancellationTokenSource();
76 | var enumerator = dataPointIterator.GetAsyncEnumerator(cts.Token);
77 |
78 | var actual = new List();
79 | await enumerator.MoveNextAsync();
80 | actual.Add(enumerator.Current);
81 | await enumerator.MoveNextAsync();
82 | actual.Add(enumerator.Current);
83 | cts.Cancel();
84 |
85 | DataPoint[] res = null;
86 | Assert.ThrowsAsync(async () => res = await dataPointIterator.ToArrayAsync(cts.Token));
87 |
88 | CollectionAssert.AreEqual(expected, actual);
89 | Assert.IsNull(res);
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Compression/SwingingDoorCompressionTests/ToListAsync.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using NUnit.Framework;
9 |
10 | namespace gfoidl.DataCompression.Tests.Compression.SwingingDoorCompressionTests
11 | {
12 | public class ToListAsync : Base
13 | {
14 | [Test, TestCaseSource(typeof(Base), nameof(Base.IAsyncEnumerableTestCases))]
15 | public async Task Data_given_as_IAsyncEnumerable___OK(double compressionDeviation, IAsyncEnumerable rawData, IEnumerable expectedData)
16 | {
17 | var sut = new SwingingDoorCompression(compressionDeviation);
18 | var data = rawData;
19 | var expected = expectedData.ToList();
20 |
21 | var actual = await sut.ProcessAsync(data).ToListAsync();
22 |
23 | CollectionAssert.AreEqual(expected, actual);
24 | }
25 | //---------------------------------------------------------------------
26 | [Test]
27 | public async Task Data_IAsyncEnumerable_with_maxDeltaX___OK()
28 | {
29 | var sut = new SwingingDoorCompression(1d, 6d);
30 | var data = RawDataAsync(RawDataForMaxDelta());
31 | var expected = ExpectedForMaxDelta().ToList();
32 |
33 | var actual = await sut.ProcessAsync(data).ToListAsync();
34 |
35 | CollectionAssert.AreEqual(expected, actual);
36 | }
37 | //---------------------------------------------------------------------
38 | [Test, TestCaseSource(typeof(Base), nameof(Base.IAsyncEnumerableTestCases))]
39 | public async Task IEnumerable_iterated_and_ToList___OK(double compressionDeviation, IAsyncEnumerable rawData, IEnumerable expectedData)
40 | {
41 | var sut = new SwingingDoorCompression(compressionDeviation);
42 | var data = rawData;
43 | var expected = expectedData.ToList();
44 |
45 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
46 | var enumerator = dataPointIterator.GetAsyncEnumerator();
47 |
48 | await enumerator.MoveNextAsync();
49 | await enumerator.MoveNextAsync();
50 | var actual = await dataPointIterator.ToListAsync();
51 |
52 | CollectionAssert.AreEqual(expected, actual);
53 | }
54 | //---------------------------------------------------------------------
55 | [Test]
56 | public async Task Cancellation___OK()
57 | {
58 | var sut = new SwingingDoorCompression(1d);
59 | var data = RawDataAsync(RawDataForTrend());
60 | var expected = ExpectedForTrend().Take(2).ToList();
61 |
62 | DataPointIterator dataPointIterator = sut.ProcessAsync(data);
63 | var cts = new CancellationTokenSource();
64 | var enumerator = dataPointIterator.GetAsyncEnumerator(cts.Token);
65 |
66 | var actual = new List();
67 | await enumerator.MoveNextAsync();
68 | actual.Add(enumerator.Current);
69 | await enumerator.MoveNextAsync();
70 | actual.Add(enumerator.Current);
71 | cts.Cancel();
72 |
73 | List res = null;
74 | Assert.ThrowsAsync(async () => res = await dataPointIterator.ToListAsync(cts.Token));
75 |
76 | CollectionAssert.AreEqual(expected, actual);
77 | Assert.IsNull(res);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Constants.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | namespace gfoidl.DataCompression.Tests
4 | {
5 | internal static class Constants
6 | {
7 | public const double Epsilon = 1e-8;
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/DataPointIteratorTests/Empty.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Threading.Tasks;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.DataPointIteratorTests
8 | {
9 | [TestFixture]
10 | public class Empty
11 | {
12 | [Test]
13 | public void MoveNext___false()
14 | {
15 | DataPointIterator sut = DataPointIterator.Empty;
16 |
17 | Assert.IsFalse(sut.MoveNext());
18 | Assert.AreSame(sut, sut.Clone());
19 | Assert.AreSame(Array.Empty(), sut.ToArray());
20 | Assert.AreEqual(0, sut.ToList().Count);
21 | }
22 | //---------------------------------------------------------------------
23 | #if NETCOREAPP
24 | [Test]
25 | public async Task MoveNextAsync___false()
26 | {
27 | DataPointIterator sut = DataPointIterator.Empty;
28 |
29 | Assert.AreSame(Array.Empty(), await sut.ToArrayAsync());
30 | Assert.AreEqual(0, (await sut.ToListAsync()).Count);
31 | }
32 | #endif
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/DataPointSerializerTests/Roundtrip.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 | using NUnit.Framework;
7 |
8 | namespace gfoidl.DataCompression.Tests.DataPointSerializerTests
9 | {
10 | [TestFixture]
11 | public class Roundtrip
12 | {
13 | private string _tmpFile;
14 | //---------------------------------------------------------------------
15 | [SetUp]
16 | public void SetUp() => _tmpFile = Path.GetTempFileName();
17 | //---------------------------------------------------------------------
18 | [TearDown]
19 | public void TearDown()
20 | {
21 | try
22 | {
23 | File.Delete(_tmpFile);
24 | }
25 | catch { }
26 | }
27 | //---------------------------------------------------------------------
28 | [Test]
29 | public void Write_Read_roundtrip___OK([Values(true, false)] bool writeHeader)
30 | {
31 | DataPoint[] dataPoints =
32 | {
33 | DataPoint.Origin,
34 | new DataPoint(1, 2),
35 | new DataPoint(2, -1)
36 | };
37 |
38 | var sut = new DataPointSerializer();
39 | string file = _tmpFile;
40 |
41 | if (writeHeader)
42 | {
43 | sut.Write(file, dataPoints, header: ("x", "y"));
44 | }
45 | else
46 | {
47 | sut.Write(file, dataPoints);
48 | }
49 | DataPoint[] actual = sut.Read(file, firstLineIsHeader: writeHeader).ToArray();
50 |
51 | CollectionAssert.AreEqual(dataPoints, actual);
52 | }
53 | //---------------------------------------------------------------------
54 | [Test]
55 | public void Write_Read_roundtrip_with_datetime___OK([Values(true, false)] bool writeHeader)
56 | {
57 | DateTime now = new DateTime(2019, 12, 16, 21, 57, 13);
58 | DateTime[] dts =
59 | {
60 | now.AddMinutes(-12),
61 | now
62 | };
63 |
64 | DataPoint[] dataPoints =
65 | {
66 | new DataPoint(dts[0], 2),
67 | new DataPoint(dts[1], -1)
68 | };
69 |
70 | var sut = new DataPointSerializer();
71 | string file = _tmpFile;
72 |
73 | const string datetimeFormat = "yyyy-MM-dd:HHmmss";
74 |
75 | if (writeHeader)
76 | {
77 | sut.Write(file, dataPoints, header: ("x", "y"), dateTimeFormat: datetimeFormat);
78 | }
79 | else
80 | {
81 | sut.Write(file, dataPoints, dateTimeFormat: datetimeFormat);
82 | }
83 | DataPoint[] actual = sut.Read(file, firstLineIsHeader: writeHeader, dateTimeFormat: datetimeFormat).ToArray();
84 |
85 | Assert.Multiple(() =>
86 | {
87 | Assert.AreEqual(2, actual.Length);
88 |
89 | Assert.AreEqual(dts[0], new DateTime((long)(actual[0].X)));
90 | Assert.AreEqual(dataPoints[0].Y, actual[0].Y, 1e-3);
91 |
92 | Assert.AreEqual(dts[1], new DateTime((long)(actual[1].X)));
93 | Assert.AreEqual(dataPoints[1].Y, actual[1].Y, 1e-3);
94 | });
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/DataPointTests/CalculatePoint.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.DataPointTests
8 | {
9 | [TestFixture]
10 | public class CalculatePoint
11 | {
12 | [Test]
13 | [TestCase(double.MinValue)]
14 | [TestCase(double.MaxValue)]
15 | [TestCase(double.NegativeInfinity)]
16 | [TestCase(double.PositiveInfinity)]
17 | [TestCase(double.NaN)]
18 | [TestCase(0)]
19 | [TestCase(1)]
20 | [TestCase(Math.PI)]
21 | public void X_same_as_of_Point___same_point_returned(double gradient)
22 | {
23 | DataPoint a = (42, 42);
24 |
25 | double actual = a.CalculatePoint(gradient, a.X);
26 |
27 | Assert.AreEqual(a.Y, actual);
28 | }
29 | //---------------------------------------------------------------------
30 | [Test]
31 | [TestCaseSource(nameof(Point_gradient_x_given___correct_Point_returned_TestCases))]
32 | public void Point_gradient_x_given___correct_Point_returned(double gradient, double x, (double X, double Y) expected)
33 | {
34 | DataPoint a = (1d, 1d);
35 |
36 | double actual = a.CalculatePoint(gradient, x);
37 |
38 | Assert.AreEqual(expected.Y, actual, 1e-6, "y");
39 | }
40 | //---------------------------------------------------------------------
41 | private static IEnumerable Point_gradient_x_given___correct_Point_returned_TestCases()
42 | {
43 | yield return new TestCaseData( 1.5, 2d, (2d, 2.5));
44 | yield return new TestCaseData( 1.5, 0d, (0d, -0.5));
45 | yield return new TestCaseData(-1.5, 2d, (2d, -0.5));
46 | yield return new TestCaseData(-1.5, 0d, (0d, 2.5));
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/DataPointTests/Ctor.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using NUnit.Framework;
5 |
6 | namespace gfoidl.DataCompression.Tests.DataPointTests
7 | {
8 | [TestFixture]
9 | public class Ctor
10 | {
11 | [Test]
12 | public void X_and_Y_given___correct_property_values(
13 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double x,
14 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double y)
15 | {
16 | var actual = new DataPoint(x, y);
17 |
18 | Assert.AreEqual(x, actual.X, Constants.Epsilon);
19 | Assert.AreEqual(y, actual.Y, Constants.Epsilon);
20 | }
21 | //---------------------------------------------------------------------
22 | [Test]
23 | public void Tuple_given___correct_property_values(
24 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double x,
25 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double y)
26 | {
27 | (double x, double y) tuple = (x, y);
28 |
29 | var actual = new DataPoint(tuple);
30 |
31 | Assert.AreEqual(x, actual.X, Constants.Epsilon);
32 | Assert.AreEqual(y, actual.Y, Constants.Epsilon);
33 | }
34 | //---------------------------------------------------------------------
35 | [Test]
36 | public void Tuple_with_DateTime_implicit___correct_property_values()
37 | {
38 | (DateTime Now, double Y) tuple = (DateTime.Now, 1.23);
39 |
40 | DataPoint actual = tuple;
41 |
42 | Assert.AreEqual(tuple.Now.Ticks, actual.X);
43 | Assert.AreEqual(tuple.Y, actual.Y);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/DataPointTests/Equals.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using NUnit.Framework;
4 |
5 | namespace gfoidl.DataCompression.Tests.DataPointTests
6 | {
7 | [TestFixture]
8 | public class Equals
9 | {
10 | [Test]
11 | public void Type_other_than_DataPoint_given___false()
12 | {
13 | var sut = new DataPoint();
14 | object o = new object();
15 |
16 | bool actual = sut.Equals(o);
17 |
18 | Assert.IsFalse(actual);
19 | }
20 | //---------------------------------------------------------------------
21 | [Test]
22 | public void Same_other_given___true(
23 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double x,
24 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double y)
25 | {
26 | var sut = new DataPoint(x, y);
27 | var other = new DataPoint(x, y);
28 |
29 | bool actual = sut.Equals(other);
30 | Assert.IsTrue(actual, "Equals");
31 |
32 | actual = sut == other;
33 | Assert.IsTrue(actual, "==");
34 | }
35 | //---------------------------------------------------------------------
36 | [Test]
37 | public void Same_other_as_object_given___true(
38 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double x,
39 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double y)
40 | {
41 | var sut = new DataPoint(x, y);
42 | object other = new DataPoint(x, y);
43 |
44 | bool actual = sut.Equals(other);
45 |
46 | Assert.IsTrue(actual);
47 | }
48 | //---------------------------------------------------------------------
49 | [Test]
50 | public void Different_other_given___true()
51 | {
52 | var sut = new DataPoint(0, 0);
53 | var other = new DataPoint(1e-150, 1e-150);
54 |
55 | bool actual = sut.Equals(other);
56 | Assert.IsFalse(actual, "Equals");
57 |
58 | actual = sut == other;
59 | Assert.IsFalse(actual, "==");
60 | }
61 | //---------------------------------------------------------------------
62 | [Test]
63 | public void Different_other_as_object_given___true()
64 | {
65 | var sut = new DataPoint(0, 0);
66 | var other = new DataPoint(1e-150, 1e-150);
67 |
68 | bool actual = sut.Equals(other);
69 |
70 | Assert.IsFalse(actual);
71 | }
72 | //---------------------------------------------------------------------
73 | [Test]
74 | public void Test_with_allowedDelta()
75 | {
76 | var sut = new DataPoint(3, 3);
77 | var other = new DataPoint(3.1, 2.9);
78 |
79 | bool actual = sut.Equals(other, 0.1001);
80 |
81 | Assert.IsTrue(actual);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/DataPointTests/GetHashCode.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using NUnit.Framework;
4 |
5 | namespace gfoidl.DataCompression.Tests.DataPointTests
6 | {
7 | [TestFixture]
8 | public class GetHashCode
9 | {
10 | /*
11 | * Rule:
12 | * Equal object must have the same hash code!
13 | * Nothing more, nothing less.
14 | */
15 | [Test]
16 | public void Two_equal_DataPoints___same_hash_code(
17 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double x,
18 | [Values(double.MinValue, double.MinValue + 1, 0, double.MaxValue - 1, double.MaxValue)]double y)
19 | {
20 | var sut = new DataPoint(x, y);
21 | var other = new DataPoint(x, y);
22 |
23 | int h1 = sut.GetHashCode();
24 | int h2 = sut.GetHashCode();
25 |
26 | Assert.AreEqual(h1, h2);
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/DataPointTests/Gradient.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.DataPointTests
8 | {
9 | [TestFixture]
10 | public class Gradient
11 | {
12 | [Test]
13 | public void Gradient_to_same_point___throws_ArgumentException()
14 | {
15 | var a = new DataPoint(1, 1);
16 | var b = a;
17 |
18 | Assert.Throws(() => a.Gradient(b, false));
19 | }
20 | //---------------------------------------------------------------------
21 | [Test]
22 | [TestCaseSource(nameof(A_and_B_given___OK_TestCases))]
23 | public double A_and_B_given___OK((double, double) ta, (double, double) tb)
24 | {
25 | DataPoint a = ta;
26 | DataPoint b = tb;
27 |
28 | return a.Gradient(b);
29 | }
30 | //---------------------------------------------------------------------
31 | private static IEnumerable A_and_B_given___OK_TestCases()
32 | {
33 | yield return new TestCaseData((0d, 0d), ( 0d, 0d)).Returns(0d);
34 | yield return new TestCaseData((0d, 0d), ( 1d, 1d)).Returns(1d);
35 | yield return new TestCaseData((0d, 0d), ( 1d, -1d)).Returns(-1d);
36 | yield return new TestCaseData((0d, 0d), ( 1d, 0d)).Returns(0d);
37 | yield return new TestCaseData((0d, 0d), (-1d, 0d)).Returns(0d);
38 | yield return new TestCaseData((0d, 0d), ( 0d, 1d)).Returns(double.PositiveInfinity);
39 | yield return new TestCaseData((0d, 0d), ( 0d, -1d)).Returns(double.NegativeInfinity);
40 | yield return new TestCaseData((0d, 0d), ( 4d, 3d)).Returns(3d / 4d);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/DataPointTests/ToTimeValue.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using NUnit.Framework;
5 |
6 | namespace gfoidl.DataCompression.Tests.DataPointTests
7 | {
8 | [TestFixture]
9 | public class ToTimeValue
10 | {
11 | [Test]
12 | public void DateTime_and_value_given___OK()
13 | {
14 | var dt = new DateTime(1982, 7, 22, 23, 35, 40);
15 | double value = Math.PI;
16 |
17 | var sut = new DataPoint(dt, value);
18 |
19 | var actual = sut.ToTimeValue();
20 |
21 | Assert.AreEqual(dt, actual.Time);
22 | Assert.AreEqual(value, actual.Value);
23 | }
24 | //---------------------------------------------------------------------
25 | [Test]
26 | public void Implicit_conversion___OK()
27 | {
28 | var dt = new DateTime(1982, 7, 22, 23, 35, 40);
29 | double value = Math.PI;
30 |
31 | var sut = new DataPoint(dt, value);
32 |
33 | (DateTime Time, double Value) actual = sut;
34 |
35 | Assert.AreEqual(dt, actual.Time);
36 | Assert.AreEqual(value, actual.Value);
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/ExtensionMethodsTests/Base.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.ExtensionMethodsTests
8 | {
9 | [TestFixture]
10 | public abstract class Base
11 | {
12 | protected static IEnumerable GetDataPoints()
13 | {
14 | yield return new DataPoint(0, 0);
15 | yield return new DataPoint(1, 1);
16 | }
17 | //---------------------------------------------------------------------
18 | #if NETCOREAPP
19 | protected static async IAsyncEnumerable GetDataPointsAsync()
20 | {
21 | foreach (DataPoint dp in GetDataPoints())
22 | {
23 | await Task.Yield();
24 | yield return dp;
25 | }
26 | }
27 | #endif
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/ExtensionMethodsTests/DeadBandCompression.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.ExtensionMethodsTests
8 | {
9 | public class DeadBandCompression : Base
10 | {
11 | [Test]
12 | public void Data_is_null___throws_ArgumentNull()
13 | {
14 | IEnumerable data = null;
15 |
16 | Assert.Throws(() => data.DeadBandCompression(0.1));
17 | }
18 | //---------------------------------------------------------------------
19 | [Test]
20 | public void DataPoints_given___OK()
21 | {
22 | IEnumerable dataPoints = GetDataPoints();
23 |
24 | DataPointIterator actual = dataPoints.DeadBandCompression(0.1);
25 |
26 | Assert.IsNotNull(actual);
27 | }
28 | //---------------------------------------------------------------------
29 | [Test]
30 | public void DataPoints_given_with_TimeSpan___OK()
31 | {
32 | IEnumerable dataPoints = GetDataPoints();
33 |
34 | DataPointIterator actual = dataPoints.DeadBandCompression(0.1, TimeSpan.FromSeconds(1));
35 |
36 | Assert.IsNotNull(actual);
37 | }
38 | //---------------------------------------------------------------------
39 | #if NETCOREAPP
40 | [Test]
41 | public void DataPoints_given_async___OK()
42 | {
43 | IAsyncEnumerable dataPoints = GetDataPointsAsync();
44 |
45 | DataPointIterator actual = dataPoints.DeadBandCompressionAsync(0.1);
46 |
47 | Assert.IsNotNull(actual);
48 | }
49 | //---------------------------------------------------------------------
50 | [Test]
51 | public void DataPoints_given_with_TimeSpan_async___OK()
52 | {
53 | IAsyncEnumerable dataPoints = GetDataPointsAsync();
54 |
55 | DataPointIterator actual = dataPoints.DeadBandCompressionAsync(0.1, TimeSpan.FromSeconds(1));
56 |
57 | Assert.IsNotNull(actual);
58 | }
59 | #endif
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/ExtensionMethodsTests/NoCompression.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using NUnit.Framework;
7 |
8 | namespace gfoidl.DataCompression.Tests.ExtensionMethodsTests
9 | {
10 | public class NoCompression : Base
11 | {
12 | [Test]
13 | public void Data_is_null___throws_ArgumentNull()
14 | {
15 | IEnumerable data = null;
16 |
17 | Assert.Throws(() => data.NoCompression());
18 | }
19 | //---------------------------------------------------------------------
20 | [Test]
21 | public void DataPoints_given___OK()
22 | {
23 | IEnumerable dataPoints = GetDataPoints();
24 |
25 | DataPointIterator actual = dataPoints.NoCompression();
26 |
27 | Assert.IsNotNull(actual);
28 | }
29 | //---------------------------------------------------------------------
30 | #if NETCOREAPP
31 | [Test]
32 | public void DataPoints_given_async___OK()
33 | {
34 | IAsyncEnumerable dataPoints = GetDataPointsAsync();
35 |
36 | DataPointIterator actual = dataPoints.NoCompressionAsync();
37 |
38 | Assert.IsNotNull(actual);
39 | }
40 | #endif
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/ExtensionMethodsTests/SwingingDoorCompression.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.ExtensionMethodsTests
8 | {
9 | public class SwingingDoorCompression : Base
10 | {
11 | [Test]
12 | public void Data_is_null___throws_ArgumentNull()
13 | {
14 | IEnumerable data = null;
15 |
16 | Assert.Throws(() => data.SwingingDoorCompression(0.1));
17 | }
18 | //---------------------------------------------------------------------
19 | [Test]
20 | public void DataPoints_given___OK()
21 | {
22 | IEnumerable dataPoints = GetDataPoints();
23 |
24 | DataPointIterator actual = dataPoints.SwingingDoorCompression(0.1);
25 |
26 | Assert.IsNotNull(actual);
27 | }
28 | //---------------------------------------------------------------------
29 | [Test]
30 | public void DataPoints_given_with_TimeSpan___OK()
31 | {
32 | IEnumerable dataPoints = GetDataPoints();
33 |
34 | DataPointIterator actual = dataPoints.SwingingDoorCompression(0.1, TimeSpan.FromSeconds(1), minTime: null);
35 |
36 | Assert.IsNotNull(actual);
37 | }
38 | //---------------------------------------------------------------------
39 | #if NETCOREAPP
40 | [Test]
41 | public void DataPoints_given_async___OK()
42 | {
43 | IAsyncEnumerable dataPoints = GetDataPointsAsync();
44 |
45 | DataPointIterator actual = dataPoints.SwingingDoorCompressionAsync(0.1);
46 |
47 | Assert.IsNotNull(actual);
48 | }
49 | //---------------------------------------------------------------------
50 | [Test]
51 | public void DataPoints_given_with_TimeSpan_async___OK()
52 | {
53 | IAsyncEnumerable dataPoints = GetDataPointsAsync();
54 |
55 | DataPointIterator actual = dataPoints.SwingingDoorCompressionAsync(0.1, TimeSpan.FromSeconds(1), minTime: null);
56 |
57 | Assert.IsNotNull(actual);
58 | }
59 | #endif
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/MySetUpClass.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | #if !NETCOREAPP
4 |
5 | using System;
6 | using NUnit.Framework;
7 |
8 | namespace gfoidl.DataCompression.Tests
9 | {
10 | [SetUpFixture]
11 | public class MySetUpClass
12 | {
13 | [OneTimeSetUp]
14 | public void OneTimeSetUp()
15 | {
16 | Environment.CurrentDirectory = TestContext.CurrentContext.TestDirectory;
17 | TestContext.Progress.WriteLine($"Directory set to {Environment.CurrentDirectory}");
18 | }
19 | }
20 | }
21 | #endif
22 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Wrappers/ArrayWrapperTests/Ctor.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using gfoidl.DataCompression.Wrappers;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.Wrappers.ArrayWrapperTests
8 | {
9 | [TestFixture]
10 | public class Ctor
11 | {
12 | [Test]
13 | public void List_is_null___throws_ArgumentNull()
14 | {
15 | Assert.Throws(() => new ArrayWrapper(null));
16 | }
17 | //---------------------------------------------------------------------
18 | [Test]
19 | public void List_is_not_null___OK()
20 | {
21 | int[] array = { 0, 1, 2 };
22 |
23 | var actual = new ArrayWrapper(array);
24 |
25 | Assert.IsNotNull(actual);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Wrappers/ArrayWrapperTests/Indexer.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using gfoidl.DataCompression.Wrappers;
4 | using NUnit.Framework;
5 |
6 | namespace gfoidl.DataCompression.Tests.Wrappers.ArrayWrapperTests
7 | {
8 | [TestFixture]
9 | public class Indexer
10 | {
11 | [Test]
12 | public void Get___OK()
13 | {
14 | int[] array = { 0, 1, 2 };
15 | var sut = new ArrayWrapper(array);
16 |
17 | int actual = sut[1];
18 |
19 | Assert.AreEqual(array[1], actual);
20 | }
21 | //---------------------------------------------------------------------
22 | [Test]
23 | public void Set___OK()
24 | {
25 | int[] array = { 0, 1, 2 };
26 | var sut = new ArrayWrapper(array);
27 |
28 | sut[2] = 42;
29 |
30 | Assert.AreEqual(42, array[2]);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Wrappers/ArrayWrapperTests/NotImplementedMembers.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections;
5 | using gfoidl.DataCompression.Wrappers;
6 | using NUnit.Framework;
7 |
8 | namespace gfoidl.DataCompression.Tests.Wrappers.ArrayWrapperTests
9 | {
10 | [TestFixture]
11 | public class NotImplementedMembers
12 | {
13 | [Test]
14 | public void Not_implemented_members___throws_NotSupported()
15 | {
16 | int[] array = { 0, 1, 2 };
17 | var sut = new ArrayWrapper(array);
18 |
19 | Assert.Throws(() => Assert.IsFalse(sut.IsReadOnly));
20 | Assert.Throws(() => sut.Add(42));
21 | Assert.Throws(() => sut.Clear());
22 | Assert.Throws(() => sut.Contains(1));
23 | Assert.Throws(() => sut.CopyTo(new int[3], 0));
24 | Assert.Throws(() => sut.GetEnumerator());
25 | Assert.Throws(() => sut.IndexOf(1));
26 | Assert.Throws(() => sut.Insert(0, 0));
27 | Assert.Throws(() => sut.Remove(1));
28 | Assert.Throws(() => sut.RemoveAt(0));
29 | Assert.Throws(() => (sut as IEnumerable)?.GetEnumerator());
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Wrappers/ListWrapperTests/Ctor.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using gfoidl.DataCompression.Wrappers;
6 | using NUnit.Framework;
7 |
8 | namespace gfoidl.DataCompression.Tests.Wrappers.ListWrapperTests
9 | {
10 | [TestFixture]
11 | public class Ctor
12 | {
13 | [Test]
14 | public void List_is_null___throws_ArgumentNull()
15 | {
16 | Assert.Throws(() => new ListWrapper(null));
17 | }
18 | //---------------------------------------------------------------------
19 | [Test]
20 | public void List_is_not_null___OK()
21 | {
22 | var list = new List { 0, 1, 2 };
23 |
24 | var actual = new ListWrapper(list);
25 |
26 | Assert.IsNotNull(actual);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Wrappers/ListWrapperTests/Indexer.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System.Collections.Generic;
4 | using gfoidl.DataCompression.Wrappers;
5 | using NUnit.Framework;
6 |
7 | namespace gfoidl.DataCompression.Tests.Wrappers.ListWrapperTests
8 | {
9 | [TestFixture]
10 | public class Indexer
11 | {
12 | [Test]
13 | public void Get___OK()
14 | {
15 | var list = new List { 0, 1, 2 };
16 | var sut = new ListWrapper(list);
17 |
18 | int actual = sut[1];
19 |
20 | Assert.AreEqual(list[1], actual);
21 | }
22 | //---------------------------------------------------------------------
23 | [Test]
24 | public void Set___OK()
25 | {
26 | var list = new List { 0, 1, 2 };
27 | var sut = new ListWrapper(list);
28 |
29 | sut[2] = 42;
30 |
31 | Assert.AreEqual(42, list[2]);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/Wrappers/ListWrapperTests/NotImplementedMembers.cs:
--------------------------------------------------------------------------------
1 | // (c) gfoidl, all rights reserved
2 |
3 | using System;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 | using gfoidl.DataCompression.Wrappers;
7 | using NUnit.Framework;
8 |
9 | namespace gfoidl.DataCompression.Tests.Wrappers.ListWrapperTests
10 | {
11 | [TestFixture]
12 | public class NotImplementedMembers
13 | {
14 | [Test]
15 | public void Not_implemented_members___throws_NotSupported()
16 | {
17 | var list = new List { 0, 1, 2 };
18 | var sut = new ListWrapper(list);
19 |
20 | Assert.Throws(() => Assert.IsFalse(sut.IsReadOnly));
21 | Assert.Throws(() => sut.Add(42));
22 | Assert.Throws(() => sut.Clear());
23 | Assert.Throws(() => sut.Contains(1));
24 | Assert.Throws(() => sut.CopyTo(new int[3], 0));
25 | Assert.Throws(() => sut.GetEnumerator());
26 | Assert.Throws(() => sut.IndexOf(1));
27 | Assert.Throws(() => sut.Insert(0, 0));
28 | Assert.Throws(() => sut.Remove(1));
29 | Assert.Throws(() => sut.RemoveAt(0));
30 | Assert.Throws(() => (sut as IEnumerable)?.GetEnumerator());
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/gfoidl.DataCompression.Tests/gfoidl.DataCompression.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(StandardTestTfms)
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------