00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 from __future__ import division
00015
00016 from math import exp
00017
00018 from random import seed
00019 from random import random
00020
00021 from enhanced_grid import Grid2D
00022
00023 newSampleCount = 1000
00024 THRESHOLD = 0.001
00025
00026
00027
00028
00029 def lerp(value, inputMin, inputMax, outputMin, outputMax):
00030 if value >= inputMax:
00031 return outputMax
00032
00033 return ramp(value, inputMin, inputMax, outputMin, outputMax)
00034
00035
00036 def sigmoid(value, inputMin, inputMax, outputMin, outputMax):
00037 w = exp((-2 * value + (inputMax + inputMin))/ (inputMax - inputMin))
00038
00039 return (outputMax - outputMin) / (1 + w) + outputMin
00040
00041
00042
00043
00044 def ramp(value, inputMin, inputMax, outputMin, outputMax):
00045 if value <= inputMin:
00046 return outputMin
00047
00048 return line(value, inputMin, inputMax, outputMin, outputMax)
00049
00050
00051
00052 def line(value, inputMin, inputMax, outputMin, outputMax):
00053 return outputMin + ((value - inputMin) * (outputMax - outputMin) / (inputMax - inputMin))
00054
00055
00056
00057
00058
00059
00060
00061 class XYResponseCurve:
00062
00063
00064
00065
00066
00067
00068
00069 def __init__(self, inputSamples, outputSamples):
00070 self.count = len(inputSamples)
00071
00072 if self.count != len(outputSamples):
00073 raise Exception('Number of input samples does not match number of output samples')
00074
00075 self.inputSamples = [0] * self.count
00076 self.outputSamples = [0] * self.count
00077
00078 for i in range(self.count):
00079 self.inputSamples[i] = inputSamples[i];
00080 self.outputSamples[i] = outputSamples[i];
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 def __call__(self, input):
00095 if input <= self.inputSamples[0]:
00096 return self.outputSamples[0];
00097
00098
00099 if input >= self.inputSamples[-1]:
00100 return self.outputSamples[- 1]
00101
00102 index = self.findInputIndex(input)
00103
00104
00105 x1 = self.inputSamples[index + 1]
00106 x0 = self.inputSamples[index]
00107
00108 tau = (input - x0) / (x1 - x0)
00109 y1 = self.outputSamples[index + 1]
00110 y0 = self.outputSamples[index]
00111
00112 return (y1 - y0) * tau + y0
00113
00114
00115 def makeInverse(self):
00116 tmp = self.inputSamples
00117 self.inputSamples = self.outputSamples
00118 self.outputSamples = tmp
00119
00120
00121
00122 def findInputIndex(self, input):
00123 min = 0
00124 max = self.count
00125
00126 while max > min + 1:
00127 mid = (max + min) // 2
00128
00129 if input < self.inputSamples[mid]:
00130 max = mid
00131 else:
00132 min = mid
00133
00134 return min
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 class ResponseCurve:
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 def __init__(self, inputMin, inputMax, outputSamples):
00157 self.inputMin = inputMin
00158 self.inputMax = inputMax
00159 self.count = len(outputSamples)
00160 self.period = (inputMax - inputMin) / (self.count - 1)
00161
00162 self.outputSamples = [0] * self.count
00163
00164 for i in range(self.count):
00165 self.outputSamples[i] = outputSamples[i]
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 def __call__ (self, input):
00180 if input <= self.inputMin:
00181 return self.outputSamples[0]
00182
00183 if input >= self.inputMax:
00184 return self.outputSamples[-1]
00185
00186
00187 index = int((input - self.inputMin)/(self.period))
00188 inputSampleMin = self.inputMin + self.period * index
00189
00190 return lerp(input, inputSampleMin, inputSampleMin + self.period, self.outputSamples[index], self.outputSamples[index + 1])
00191
00192 def getInputMin(self):
00193 return self.inputMin
00194
00195 def getInputMax(self):
00196 return self.inputMax
00197
00198 class NormalisedInputCurve:
00199 def __init__ (self, curve):
00200 self.curve = curve
00201
00202
00203
00204 def __call__(self, input):
00205
00206 return self.curve(input*(self.curve.inputMax - self.curve.inputMin) + self.curve.inputMin)
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 def make_distribution_curve(inputSamples, outputSamples):
00217 newInputMin = outputSamples[0]
00218 newInputMax = sum(outputSamples)
00219 newOutputMax = inputSamples[-1]
00220 newOutputMin = inputSamples[0]
00221
00222 oldSampleCount = len(inputSamples)
00223 accumulativeOutputSamples = [0] * oldSampleCount
00224
00225
00226
00227 accumulativeOutputSamples[0] = outputSamples[0]
00228
00229 for i in range(oldSampleCount):
00230 accumulativeOutputSamples[i] = accumulativeOutputSamples[i - 1] + outputSamples[i]
00231
00232
00233 xyCurve = XYResponseCurve(accumulativeOutputSamples, inputSamples)
00234
00235
00236 newOutputSamples = [0] * newSampleCount
00237
00238
00239 for i in range(newSampleCount):
00240 input = (i / (newSampleCount - 1)) * (newInputMax - newInputMin) + newInputMin
00241 newOutputSamples[i] = xyCurve(input)
00242
00243
00244
00245
00246
00247
00248 curve = ResponseCurve(newInputMin, newInputMax, newOutputSamples)
00249
00250
00251 curve = NormalisedInputCurve(curve)
00252
00253 return curve
00254
00255
00256
00257
00258
00259
00260
00261
00262 class Distribution2D():
00263
00264
00265
00266
00267 def __init__(self, prob_matrix, min_corner, max_corner):
00268 self.min_x, self.min_y = min_corner
00269 self.max_x, self.max_y = max_corner
00270 self.width, self.height = prob_matrix.dims
00271
00272 self.x_curve, self.y_curves = self.make_distribution(prob_matrix)
00273
00274 def __call__(self, rx, ry):
00275 x = self.x_curve(rx)
00276 xi = int(x * (self.width - 1))
00277 y = self.y_curves[xi + 1](ry)
00278
00279 return x, y
00280
00281
00282 def make_distribution(self, matrix):
00283 x_samples = [0] * self.width
00284 x_input_samples = [0] * self.width
00285 delta_x = 1 / (self.width - 1)
00286 delta_y = 1 / (self.height - 1)
00287 y_curves = [0] * self.width
00288
00289 for i in range(self.width):
00290 x_input_samples[i] = (i) * delta_x
00291 y_samples = [0] * self.height
00292 y_input_samples = [0] * self.height
00293
00294 for j in range(self.height):
00295 x_samples[i] += matrix[i,j]
00296 y_samples[j] = matrix[i,j]
00297
00298 y_input_samples[j] = (j) * delta_y
00299
00300 y_curves[i] = make_distribution_curve(y_input_samples, y_samples)
00301 x_curve = make_distribution_curve(x_input_samples, x_samples)
00302
00303 return x_curve, y_curves
00304
00305
00306
00307
00308 def distribution_from_grid(grid, x_cells, y_cells):
00309 distribution = Grid2D((x_cells, y_cells), 0)
00310 grid_w, grid_h = grid.dims
00311 w = grid_w // x_cells
00312 h = grid_h // y_cells
00313
00314 for index in grid.index_iter():
00315 i, j = index
00316 distribution[i // w, j // h] += grid[index]
00317
00318 distribution2 = Grid2D((x_cells + 1, y_cells + 1), 0)
00319 distribution2[1:, 1:] = distribution
00320
00321 return distribution2
00322
00323