@@ -161,6 +161,18 @@ def _alloc_table(self):
161161 self .table = np .ndarray (table_shape , dtype = np .float64 , buffer = self .table_sm .buf )
162162 _table_name_autoinc += 1
163163
164+ def _make_table (self ):
165+ from . import _thread_pool
166+ args = zip (repeat (self .table_name ),
167+ * (repeat (inp ) for inp in self .model .inputs ),
168+ repeat (self .model .num_states ),
169+ repeat (self .polynomial ),
170+ repeat (len (self .samples )),
171+ iter (self .samples ))
172+ rss_sum = sum (map (self ._table_kernel , args )) # Single threaded
173+ # rss_sum = sum(_thread_pool.map(self._table_kernel, list(args), chunksize=1)) # Multithreaded
174+ self .rmse = (rss_sum / self .num_states ** 2 / len (self .samples )) ** .5
175+
164176 def __del__ (self ):
165177 if self .table_sm is not None :
166178 self .table_sm .close ()
@@ -250,22 +262,11 @@ def _polynomial_basis(input1_locations, num_terms):
250262 A [:, power ] = input1_locations ** power
251263 return A
252264
253- def _make_table (self ):
254- from . import _thread_pool
255- args = zip (repeat (self .table_name ),
256- repeat (self .model .input1 ),
257- repeat (self .model .num_states ),
258- repeat (self .num_terms ),
259- repeat (len (self .samples )),
260- iter (self .samples ))
261- # rss_sum = sum(map(self._table_kernel, args)) # Single threaded
262- rss_sum = sum (_thread_pool .map (self ._table_kernel , list (args ), chunksize = 1 )) # Multithreaded
263- self .rmse = (rss_sum / self .num_states ** 2 / len (self .samples )) ** .5
264-
265265 @staticmethod
266266 def _table_kernel (args ):
267267 # Unpack the arguments.
268- table_name , input1 , num_states , num_terms , num_samples , ((bucket_index ,), data_range ) = args
268+ table_name , input1 , num_states , polynomial , num_samples , ((bucket_index ,), data_range ) = args
269+ num_terms = polynomial .num_terms
269270 (inputs_sm ,), samples_sm = MatrixSamples ._get_sm_weakref (1 )
270271 table_sm = SharedMemory (table_name , False )
271272 inputs_shape = (num_samples ,)
@@ -335,26 +336,45 @@ def __init__(self, samples, polynomial):
335336 self ._alloc_table ()
336337 self ._make_table ()
337338
338- def _make_table (self ):
339- self .table = np .empty ([self .input1 .num_buckets , self .input2 .num_buckets ,
340- self .num_states , self .num_states , self .num_terms ])
341- def compute_chunk (bucket_data ):
342- (bucket_index1 , bucket_index2 ), (input1_values , input2_values ), exact_data = bucket_data
343- # Scale the inputs into the range [0,1].
344- input1_locations = self .input1 .get_bucket_value (input1_values ) - bucket_index1
345- input2_locations = self .input2 .get_bucket_value (input2_values ) - bucket_index2
346- # Make an approximation for each entry in the matrix.
347- A = np .empty ([len (input1_values ), self .num_terms ])
348- for term , (power1 , power2 ) in enumerate (self .polynomial .terms ):
349- A [:, term ] = (input1_locations ** power1 ) * (input2_locations ** power2 )
350- B = exact_data .reshape (- 1 , self .num_states ** 2 )
351- coef , rss = np .linalg .lstsq (A , B , rcond = None )[:2 ]
352- coef = coef .reshape (self .num_terms , self .num_states , self .num_states ).transpose (1 ,2 ,0 )
353- self .table [bucket_index1 , bucket_index2 , :, :, :] = coef
354- return np .sum (rss )
355- from . import _thread_pool
356- rss_sum = sum (_thread_pool .map (compute_chunk , self .samples , chunksize = 1 ))
357- self .rmse = (rss_sum / self .num_states ** 2 / len (self .samples )) ** .5
339+ @staticmethod
340+ def _polynomial_basis (input1_locations , input2_locations , polynomial ):
341+ # Make an approximation for each entry in the matrix.
342+ A = np .empty ([len (input1_locations ), polynomial .num_terms ])
343+ for term , (power1 , power2 ) in enumerate (polynomial .terms ):
344+ A [:, term ] = (input1_locations ** power1 ) * (input2_locations ** power2 )
345+ return A
346+
347+ @staticmethod
348+ def _table_kernel (args ):
349+ # Unpack the arguments.
350+ (table_name , input1 , input2 , num_states , polynomial ,
351+ num_samples , ((bucket_index1 , bucket_index2 ,), data_range )) = args
352+ num_terms = polynomial .num_terms
353+ # Setup the shared memory.
354+ (input1_sm , input2_sm ), samples_sm = MatrixSamples ._get_sm_weakref (2 )
355+ table_sm = SharedMemory (table_name , False )
356+ inputs_shape = (num_samples ,)
357+ samples_shape = (num_samples , num_states , num_states )
358+ table_shape = (input1 .num_buckets , input2 .num_buckets , num_states , num_states , num_terms )
359+ input1_buf = np .ndarray (inputs_shape , dtype = np .float64 , buffer = input1_sm .buf )
360+ input2_buf = np .ndarray (inputs_shape , dtype = np .float64 , buffer = input2_sm .buf )
361+ samples_buf = np .ndarray (samples_shape , dtype = np .float64 , buffer = samples_sm .buf )
362+ table_buf = np .ndarray (table_shape , dtype = np .float64 , buffer = table_sm .buf )
363+ # Slice out the current bucket's samples.
364+ num_samples = data_range [1 ] - data_range [0 ]
365+ input1_buf = input1_buf [data_range [0 ] : data_range [1 ]]
366+ input2_buf = input2_buf [data_range [0 ] : data_range [1 ]]
367+ samples_buf = samples_buf [data_range [0 ] : data_range [1 ]]
368+ # Scale the inputs into the range [0,1].
369+ input1_locations = input1 .get_bucket_value (input1_buf ) - bucket_index1
370+ input2_locations = input2 .get_bucket_value (input2_buf ) - bucket_index2
371+ #
372+ A = Approx2D ._polynomial_basis (input1_locations , input2_locations , polynomial )
373+ B = samples_buf .reshape (- 1 , num_states ** 2 )
374+ coef , rss = np .linalg .lstsq (A , B , rcond = None )[:2 ]
375+ coef = coef .reshape (num_terms , num_states , num_states ).transpose (1 ,2 ,0 )
376+ table_buf [bucket_index1 , bucket_index2 , :, :, :] = coef
377+ return np .sum (rss )
358378
359379 def approximate_matrix (self , input1 , input2 ):
360380 assert len (input1 .shape ) == 1 and input1 .shape == input2 .shape
@@ -368,3 +388,36 @@ def approximate_matrix(self, input1, input2):
368388 basis = basis .T .reshape (num_samples , 1 , 1 , self .num_terms )
369389 coef = self .table [bucket1_index , bucket2_index ]
370390 return np .sum (coef * basis , axis = - 1 )
391+
392+ @staticmethod
393+ def _error_kernel (args ):
394+ # Unpack the arguments.
395+ (table_name , power , (input1 , input2 ), polynomial , num_states ,
396+ num_samples , ((bucket_index1 , bucket_index2 ), data_range )) = args
397+ num_terms = polynomial .num_terms
398+ # Access the shared memory.
399+ (input1_sm , input2_sm ), samples_sm = MatrixSamples ._get_sm_weakref (2 )
400+ table_sm = SharedMemory (table_name , False )
401+ inputs_shape = (num_samples ,)
402+ samples_shape = (num_samples , num_states , num_states )
403+ table_shape = (input1 .num_buckets , input2 .num_buckets , num_states , num_states , num_terms )
404+ input1_buf = np .ndarray (inputs_shape , dtype = np .float64 , buffer = input1_sm .buf )
405+ input2_buf = np .ndarray (inputs_shape , dtype = np .float64 , buffer = input2_sm .buf )
406+ samples_buf = np .ndarray (samples_shape , dtype = np .float64 , buffer = samples_sm .buf )
407+ table_buf = np .ndarray (table_shape , dtype = np .float64 , buffer = table_sm .buf )
408+ # Slice out one chunk of data.
409+ num_samples = data_range [1 ] - data_range [0 ]
410+ input1_buf = input1_buf [data_range [0 ] : data_range [1 ]]
411+ input2_buf = input2_buf [data_range [0 ] : data_range [1 ]]
412+ exact = samples_buf [data_range [0 ] : data_range [1 ]]
413+ # Evaluate the approximation.
414+ input1_index , input1_location = input1 ._get_bucket_location_array (input1_buf )
415+ input2_index , input2_location = input2 ._get_bucket_location_array (input2_buf )
416+ basis = Approx2D ._polynomial_basis (input1_location , input2_location , polynomial )
417+ basis = basis .reshape (num_samples , 1 , 1 , num_terms )
418+ coef = table_buf [bucket_index1 , bucket_index2 , :, :, :]
419+ approx = np .sum (coef * basis , axis = - 1 )
420+ # Increase the timestep to 1 ms
421+ approx = np .linalg .matrix_power (approx , power )
422+ exact = np .linalg .matrix_power (exact , power )
423+ return np .max (np .abs (approx - exact ))
0 commit comments