summaryrefslogtreecommitdiff
path: root/src/logoot.js
blob: c8c7c02896af19246ec86717c146af212984ef87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
export default {

  query(property) {
    return {
      [property]: {
        $type: 'array',
        $type: ['int', 'long'],
      },
      $nor: [
        { [property]: { $gt: this.maxInt } },
        { [property]: { $lt: 0 } },
      ]
    }
  },

  get before() {
    return []
  },

  get after() {
    return [this.maxInt+1]
  },

  between(a, b, scale=100) {
    // Strip zeros and find common length
    const aLength = this.lengthWithoutZeros(a)
    const bLength = this.lengthWithoutZeros(b)
    const minLength = Math.min(aLength, bLength)

    // Initialize output
    const out = []

    // Find the break point where a[i] != b[i]
    let i = 0
    while (i < minLength && a[i] == b[i]) {
      out.push(a[i])
      i++
    }

    // Initialize upper and lower bounds for
    // sampling the last digit
    let lowerBound = 1
    let upperBound = this.maxInt

    if (i < minLength) {
      // If the break happened before we hit
      // the end of one of the arrays

      if (Math.abs(a[i] - b[i]) > 1) {
        // If a[i] and b[i] are more than one
        // away from each other, just sample
        // between them
        lowerBound = Math.min(a[i], b[i]) + 1
        upperBound = Math.max(a[i], b[i]) - 1
      } else {
        // If they are one away no integers
        // will fit in between, so add new layer
        const lesser = (a[i] < b[i])? a : b
        out.push(lesser[i])
        i++

        while (i < lesser.length && lesser[i] >= this.maxInt) {
          // If the lesser is at it's limit,
          // we will need to add even more layers
          out.push(lesser[i])
          i++
        }

        if (i < lesser.length) {
          // Sample something greater than
          // the lesser digit
          lowerBound = lesser[i] + 1
        }
      }
    } else {
      // The break happened because we hit
      // the end of one of the arrays.

      if (aLength == bLength) {
        // If they are entirely equal,
        // there is nothing in between
        // just return what we have
        return out
      }

      const longerLength = Math.max(aLength, bLength)
      const longer = (a.length == longerLength)? a : b
      while (i < longerLength && longer[i] == 0) {
        // Skip past the zeros because we can't sample
        // for digits less than zero
        out.push(0)
        i++
      }

      if (i < longerLength) {
        if (longer[i] == 1) {
          // If longer is at it's limit,
          // we still need to add another layer
          out.push(0)
        } else {
          upperBound = longer[i] - 1
        }
      }
    }

    // Create a random number in [0,1] but bias it to be small,
    // so that numbers tend to increase by a small amount.
    let random = Math.random()
    random = -Math.log(1-random)/scale
    random = Math.min(random, 1)
    
    // Finally, sample between the upper and lower bounds
    out.push(Math.floor(random * (upperBound + 1 - lowerBound)) + lowerBound)
    return out
  },

  compare(a, b) {
    // Strip zeros and find common length
    const aLength = this.lengthWithoutZeros(a)
    const bLength = this.lengthWithoutZeros(b)
    const minLength = Math.min(aLength, bLength)

    // See if there are any differences
    for (let i = 0; i < minLength; i++) {
      if (a[i] > b[i]) {
        return 1
      } else if (a[i] < b[i]) {
        return -1
      }
    }

    // If they are all the same up til now,
    // the longer one is bigger
    if (aLength > bLength) {
      return 1
    } else if (aLength < bLength) {
      return -1
    } else {
      return 0
    }
  },


  lengthWithoutZeros(a) {
    let length = a.length
    while (length > 0 && a[length - 1] == 0) {
      length--
    }
    return length
  },

  maxInt: 9007199254740991,
}