nthderivative.go 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Copyright 2017 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package s2
  15. // nthDerivativeCoder provides Nth Derivative Coding.
  16. // (In signal processing disciplines, this is known as N-th Delta Coding.)
  17. //
  18. // Good for varint coding integer sequences with polynomial trends.
  19. //
  20. // Instead of coding a sequence of values directly, code its nth-order discrete
  21. // derivative. Overflow in integer addition and subtraction makes this a
  22. // lossless transform.
  23. //
  24. // constant linear quadratic
  25. // trend trend trend
  26. // / \ / \ / \_
  27. // input |0 0 0 0 1 2 3 4 9 16 25 36
  28. // 0th derivative(identity) |0 0 0 0 1 2 3 4 9 16 25 36
  29. // 1st derivative(delta coding) | 0 0 0 1 1 1 1 5 7 9 11
  30. // 2nd derivative(linear prediction) | 0 0 1 0 0 0 4 2 2 2
  31. // -------------------------------------
  32. // 0 1 2 3 4 5 6 7 8 9 10 11
  33. // n in sequence
  34. //
  35. // Higher-order codings can break even or be detrimental on other sequences.
  36. //
  37. // random oscillating
  38. // / \ / \_
  39. // input |5 9 6 1 8 8 2 -2 4 -4 6 -6
  40. // 0th derivative(identity) |5 9 6 1 8 8 2 -2 4 -4 6 -6
  41. // 1st derivative(delta coding) | 4 -3 -5 7 0 -6 -4 6 -8 10 -12
  42. // 2nd derivative(linear prediction) | -7 -2 12 -7 -6 2 10 -14 18 -22
  43. // ---------------------------------------
  44. // 0 1 2 3 4 5 6 7 8 9 10 11
  45. // n in sequence
  46. //
  47. // Note that the nth derivative isn't available until sequence item n. Earlier
  48. // values are coded at lower order. For the above table, read 5 4 -7 -2 12 ...
  49. type nthDerivativeCoder struct {
  50. n, m int
  51. memory [10]int32
  52. }
  53. // newNthDerivativeCoder returns a new coder, where n is the derivative order of the encoder (the N in NthDerivative).
  54. // n must be within [0,10].
  55. func newNthDerivativeCoder(n int) *nthDerivativeCoder {
  56. c := &nthDerivativeCoder{n: n}
  57. if n < 0 || n > len(c.memory) {
  58. panic("unsupported n. Must be within [0,10].")
  59. }
  60. return c
  61. }
  62. func (c *nthDerivativeCoder) encode(k int32) int32 {
  63. for i := 0; i < c.m; i++ {
  64. delta := k - c.memory[i]
  65. c.memory[i] = k
  66. k = delta
  67. }
  68. if c.m < c.n {
  69. c.memory[c.m] = k
  70. c.m++
  71. }
  72. return k
  73. }
  74. func (c *nthDerivativeCoder) decode(k int32) int32 {
  75. if c.m < c.n {
  76. c.m++
  77. }
  78. for i := c.m - 1; i >= 0; i-- {
  79. c.memory[i] += k
  80. k = c.memory[i]
  81. }
  82. return k
  83. }