Source code for kona.linalg.memory


[docs]class VectorFactory(object): """ A factory object used for generating Kona's abstracted vector classes. This object also tallies up how many vectors of which kind needs to be allocated, based on the memory requirements of each optimization function. Parameters ---------- memory : KonaMemory vec_type : PrimalVector or StateVector or DualVector Attributes ---------- num_vecs : int Number of vectors requested from this factory. _memory : KonaMemory All-knowing Kona memory manager. _vec_type : DesignVector or StateVector or DualVector Kona abstracted vector type associated with this factory """ def __init__(self, memory, vec_type=None): self.num_vecs = 0 self._memory = memory if vec_type not in self._memory.vector_stack.keys(): raise TypeError('VectorFactory() >> Unknown vector type!') else: self._vec_type = vec_type
[docs] def request_num_vectors(self, count): """ Put in a request for the factory's vector type, to be used later. Parameters ---------- count : int Number of vectors requested. """ if count < 1: raise ValueError('VectorFactory() >> ' + 'Cannot request less than 1 vector.') self.num_vecs += count
[docs] def generate(self): """ Generate one abstract KonaVector of this vector factory's defined type. Returns ------- KonaVector Abstracted vector type linked to user generated memory. """ if self._memory.allocated: try: data = self._memory.pop_vector(self._vec_type) except IndexError: raise MemoryError( 'No more vector memory available. ' + 'Allocate more vectors in your algorithm initialization') return self._vec_type(self._memory, data) else: raise RuntimeError('VectorFactory() >> ' + 'Must allocate memory before generating vector.')
class KonaFile(object): def __init__(self, filename, rank): # only produce a file handle for the root processor if rank == 0: if isinstance(filename, str): self.file = open(filename, 'w', 0) else: self.file = filename else: self.file = None def write(self, string): if self.file is not None: self.file.write(string)
[docs]class KonaMemory(object): """ All-knowing Big Brother abstraction layer for Kona. Parameters ---------- solver : UserSolver A user-defined solver object that implements specific elementary tasks. Attributes ---------- solver : UserSolver A user-defined solver object that implements specific elementary tasks. primal_factory : VectorFactory Vector generator for primal space. state_factory : VectorFactory Vector generator for state space. dual_factory : VectorFactory Vector generatorfor dual space. precond_count : int Counter for tracking optimization cost. vector_stack : dict Memory stack for unused vector data. rank : int Processor rank. """ def __init__(self, solver): # assign user object self.solver = solver self.ndv = solver.num_design self.neq = solver.num_eq self.nineq = solver.num_ineq self.rank = solver.get_rank() # check if this is an IDF problem try: self.num_real_design = solver.num_real_design if self.num_real_design == self.ndv: self.num_real_design = None self.num_real_ceq = solver.num_real_ceq if self.num_real_ceq == self.neq: self.num_real_ceq = None except AttributeError: self.num_real_design = None self.num_real_ceq = None # empty design bounds self.design_lb = None self.design_ub = None # allocate vec assignments self.vector_stack = { DesignVector : [], StateVector : [], DualVectorEQ : [], DualVectorINEQ : [], } # prepare vector factories self.primal_factory = VectorFactory(self, DesignVector) self.state_factory = VectorFactory(self, StateVector) self.eq_factory = VectorFactory(self, DualVectorEQ) self.ineq_factory = VectorFactory(self, DualVectorINEQ) # cost tracking self.cost = 0 self.allocated = False
[docs] def push_vector(self, vec_type, user_data): """ Pushes an unused user vector data container into the memory stack so it can be used later in a new vector. Parameters ---------- vec_type : KonaVector Vector type of the memory stack. user_data : BaseVector Unused user vector data container. """ if user_data not in self.vector_stack[vec_type]: self.vector_stack[vec_type].append(user_data)
[docs] def pop_vector(self, vec_type): """ Take an unused user vector object out of the memory stack and serve it to the vector factory. Parameters ---------- vec_type : KonaVector Vector type to be popped from the stack. Returns ------- BaseVector User-defined vector data structure. """ if vec_type not in self.vector_stack.keys(): raise TypeError('KonaMemory.pop_vector() >> ' + 'Unknown vector type!') else: return self.vector_stack[vec_type].pop()
[docs] def allocate_memory(self): """ Absolute final stage of memory allocation. Once the number of required vectors are tallied up inside vector factories, this function will manipulate the user-defined solver object to allocate all actual, real memory required for the optimization. """ if self.allocated: raise RuntimeError('Memory already allocated, can-not re-allocate') self.vector_stack[DesignVector] = \ [BaseVector(self.ndv) for i in range(self.primal_factory.num_vecs)] self.vector_stack[StateVector] = \ self.solver.allocate_state(self.state_factory.num_vecs) self.vector_stack[DualVectorEQ] = \ [BaseVector(self.neq) for i in range(self.eq_factory.num_vecs)] self.vector_stack[DualVectorINEQ] = \ [BaseVector(self.nineq) for i in range(self.ineq_factory.num_vecs)] self.allocated = True
[docs] def open_file(self, filename): return KonaFile(filename, self.rank)
# imports at the bottom to prevent circular errors from kona.user import BaseVector, UserSolver, UserSolverIDF from kona.linalg.vectors.common import *