Fix an interpolation code-gen issue.

A bug in the hacky use of OrderedDict to function as an OrderedSet meant
that any value acceessed in a precalculation function which had already
been accessed from another precalculation function would use an
incorrect index.
This commit is contained in:
Steven Robertson 2012-07-21 13:14:09 -07:00
parent 44a826508a
commit 3a6490825b
2 changed files with 31 additions and 15 deletions

View File

@ -1,4 +1,3 @@
from collections import OrderedDict
from itertools import cycle from itertools import cycle
import numpy as np import numpy as np
@ -7,10 +6,26 @@ from cuburn.genome.util import resolve_spec
from cuburn.genome.use import Wrapper, SplineEval from cuburn.genome.use import Wrapper, SplineEval
import util import util
from util import Template, assemble_code, devlib, binsearchlib, ringbuflib from util import Template, assemble_code, devlib, binsearchlib, ringbuflib, snd
from color import yuvlib from color import yuvlib
from mwc import mwclib from mwc import mwclib
class _OrderedSet(object):
"""
A set that tracks the order in which items are added to it. Items cannot
be removed. Iterating over the set returns items in order of addition.
"""
def __init__(self):
self._vals = {}
def add(self, val):
return self._vals.setdefault(val, len(self._vals))
def __iter__(self):
return (k for k, v in sorted(self._vals.items(), key=snd))
def __len__(self):
return len(self._vals)
def __contains__(self, val):
return val in self._vals
class PackerWrapper(Wrapper): class PackerWrapper(Wrapper):
""" """
Obtain accessors in generated code. Obtain accessors in generated code.
@ -123,13 +138,12 @@ class GenomePacker(object):
# to be able to treat the direct stuff as a list so this function # to be able to treat the direct stuff as a list so this function
# doesn't unroll any more than it has to. So we separate things into # doesn't unroll any more than it has to. So we separate things into
# direct requests, and those that need precalculation. # direct requests, and those that need precalculation.
# Values of OrderedDict are unused; basically, it's just OrderedSet. self.packed_direct = _OrderedSet()
self.packed_direct = OrderedDict()
# Feel kind of bad about this, but it's just under the threshold of # Feel kind of bad about this, but it's just under the threshold of
# being worth refactoring to be agnostic to interpolation types # being worth refactoring to be agnostic to interpolation types
self.packed_direct_mag = OrderedDict() self.packed_direct_mag = _OrderedSet()
self.genome_precalc = OrderedDict() self.genome_precalc = _OrderedSet()
self.packed_precalc = OrderedDict() self.packed_precalc = _OrderedSet()
self.precalc_code = [] self.precalc_code = []
self._len = None self._len = None
@ -155,19 +169,18 @@ class GenomePacker(object):
must be available during interpolation. must be available during interpolation.
""" """
if spec.interp == 'mag': if spec.interp == 'mag':
self.packed_direct_mag[path] = None self.packed_direct_mag.add(path)
else: else:
self.packed_direct[path] = None self.packed_direct.add(path)
return self.devname(path) return self.devname(path)
def _require_pre(self, spec, path): def _require_pre(self, spec, path):
i = len(self.genome_precalc) << self.search_rounds i = self.genome_precalc.add(path) << self.search_rounds
self.genome_precalc[path] = None
func = 'catmull_rom_mag' if spec.interp == 'mag' else 'catmull_rom' func = 'catmull_rom_mag' if spec.interp == 'mag' else 'catmull_rom'
return '%s(&times[%d], &knots[%d], time)' % (func, i, i) return '%s(&times[%d], &knots[%d], time)' % (func, i, i)
def _pre_alloc(self, path): def _pre_alloc(self, path):
self.packed_precalc[path] = None self.packed_precalc.add(path)
return '%s->%s' % (self.ptr_name, '_'.join(path)) return '%s->%s' % (self.ptr_name, '_'.join(path))
def devname(self, path): def devname(self, path):
@ -180,9 +193,9 @@ class GenomePacker(object):
# At the risk of packing a few things more than once, we don't # At the risk of packing a few things more than once, we don't
# uniquify the overall precalc order, sparing us the need to implement # uniquify the overall precalc order, sparing us the need to implement
# recursive code generation # recursive code generation
direct = self.packed_direct.keys() + self.packed_direct_mag.keys() direct = list(self.packed_direct) + list(self.packed_direct_mag)
self.packed = direct + self.packed_precalc.keys() self.packed = direct + list(self.packed_precalc)
self.genome = direct + self.genome_precalc.keys() self.genome = direct + list(self.genome_precalc)
self._len = len(self.packed) self._len = len(self.packed)

View File

@ -10,6 +10,9 @@ import pycuda.compiler
import numpy as np import numpy as np
import tempita import tempita
fst = lambda (a,b): a
snd = lambda (a,b): b
def argset(obj, **kwargs): def argset(obj, **kwargs):
""" """
Allow an object with many properties to be set using one call. Allow an object with many properties to be set using one call.