import struct
import subprocess
import threading
import numpy
import scipy.optimize
_INF = float('inf')
def bits_from_float(value: float) -> int:
return struct.unpack('>l', struct.pack('>f', value))[0]
class Scorer:
def __init__(self) -> None:
self._process = subprocess.Popen(('./gamma8',),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
self._lock = threading.Lock()
def __call__(self, *args) -> float:
if len(args) == 5:
min_approx, min_255, bits_offset, bits_step, y_offset = args
elif len(args) == 4:
min_approx, min_255, bits_offset, y_offset = args
bits_step = 1 << 18
else:
raise TypeError()
if min_approx <= 0.001 or min_approx >= 1.0:
return _INF
if min_255 <= 0.001 or min_255 >= 1.0:
return _INF
if bits_offset < 0.001 or bits_offset > 0.1:
return _INF
if bits_offset > min_255:
return _INF
if bits_step <= 0 or bits_step >= 2**26:
return _INF
if y_offset < -1.0 or y_offset > 1.0:
return _INF
values = (float(min_approx), float(min_255),
float(bits_offset), int(bits_step),
float(y_offset))
line = (' '.join(str(value) for value in values) + '\n').encode('ascii')
with self._lock:
proc = self._process
assert proc, 'Scorer already closed'
proc.stdin.write(line)
proc.stdin.flush()
line = proc.stdout.readline()
return float(line.split()[0]) * 2**14
def close(self) -> None:
with self._lock:
proc = self._process
self._process = None
if proc:
proc.stdout.close()
try:
proc.wait(1)
except subprocess.TimeoutExpired:
proc.kill()
proc.wait(1)
def __enter__(self) -> 'Scorer':
return self
def __exit__(self, *_):
self.close()
def main():
with Scorer() as scorer:
x0 = numpy.array([0.00319052, 0.99549606, 0.00313369, 0.50994874])
best = scorer(*x0)
print(best)
res = scipy.optimize.minimize((lambda x: scorer(*x)), x0, method='nelder-mead',
options={'disp': True})
print(repr(res))
print('{}{}'.format(res.fun, ' improved' if res.fun < best else ''))
print('[{}]'.format(', '.join(str(value) for value in res.x)))
print('[{}]'.format(', '.join('0x{:x}'.format(bits_from_float(value)) for value in res.x)))
if __name__ == '__main__':
main()