def sample_randomly(self, count=None, random_state=None, seed=None): """Randomly sample |Parameters| from the space. Parameters ---------- count `None` or number of random parameters (see below). random_state :class:`~numpy.random.RandomState` to use for sampling. If `None`, a new random state is generated using `seed` as random seed, or the :func:`default <pymor.tools.random.default_random_state>` random state is used. seed If not `None`, a new radom state with this seed is used. Returns ------- If `count` is `None`, an inexhaustible iterator returning random |Parameters|. Otherwise a list of `count` random |Parameters|. """ assert not random_state or seed is None ranges = self.ranges random_state = get_random_state(random_state, seed) get_param = lambda: Parameter(((k, random_state.uniform(ranges[k][0], ranges[k][1], shp)) for k, shp in self.parameter_type.items())) if count is None: def param_generator(): while True: yield get_param() return param_generator() else: return [get_param() for _ in range(count)]
def sample_randomly(self, count=None, random_state=None, seed=None): """Randomly sample |Parameters| from the space. Parameters ---------- count `None` or number of random parameters (see below). random_state :class:`~numpy.random.RandomState` to use for sampling. If `None`, a new random state is generated using `seed` as random seed, or the :func:`default <pymor.tools.random.default_random_state>` random state is used. seed If not `None`, a new radom state with this seed is used. Returns ------- If `count` is `None`, an inexhaustible iterator returning random |Parameters|. Otherwise a list of `count` random |Parameters|. """ assert not random_state or seed is None ranges = self.ranges random_state = get_random_state(random_state, seed) get_param = lambda: Parameter(((k, random_state.uniform(ranges[k][0], ranges[k][1], shp)) for k, shp in self.parameter_type.items())) if count is None: def param_generator(): while True: yield get_param() return param_generator() else: return [get_param() for _ in range(count)]
def projection_shifts_init(A, E, B, shift_options): """Find starting shift parameters for low-rank ADI iteration using Galerkin projection on spaces spanned by LR-ADI iterates. See :cite:`PK16`, pp. 92-95. Parameters ---------- A The |Operator| A from the corresponding Lyapunov equation. E The |Operator| E from the corresponding Lyapunov equation. B The |VectorArray| B from the corresponding Lyapunov equation. shift_options The shift options to use (see :func:`lyap_lrcf_solver_options`). Returns ------- shifts A |NumPy array| containing a set of stable shift parameters. """ random_state = get_random_state(seed=shift_options['init_seed']) for i in range(shift_options['init_maxiter']): Q = gram_schmidt(B, atol=0, rtol=0) shifts = spla.eigvals(A.apply2(Q, Q), E.apply2(Q, Q)) shifts = shifts[shifts.real < 0] if shifts.size == 0: # use random subspace instead of span{B} (with same dimensions) B = B.random(len(B), distribution='normal', random_state=random_state) else: return shifts raise RuntimeError('Could not generate initial shifts for low-rank ADI iteration.')
def projection_shifts_init(A, E, B, shift_options): """Find starting shift parameters for low-rank ADI iteration using Galerkin projection on spaces spanned by LR-ADI iterates. See [PK16]_, pp. 92-95. Parameters ---------- A The |Operator| A from the corresponding Lyapunov equation. E The |Operator| E from the corresponding Lyapunov equation. B The |VectorArray| B from the corresponding Lyapunov equation. shift_options The shift options to use (see :func:`lyap_lrcf_solver_options`). Returns ------- shifts A |NumPy array| containing a set of stable shift parameters. """ random_state = get_random_state(seed=shift_options['init_seed']) for i in range(shift_options['init_maxiter']): Q = gram_schmidt(B, atol=0, rtol=0) shifts = spla.eigvals(A.apply2(Q, Q), E.apply2(Q, Q)) shifts = shifts[shifts.real < 0] if shifts.size == 0: # use random subspace instead of span{B} (with same dimensions) B = B.random(len(B), distribution='normal', random_state=random_state) else: return shifts raise RuntimeError('Could not generate initial shifts for low-rank ADI iteration.')
def random(self, count=1, distribution='uniform', random_state=None, seed=None, reserve=0, **kwargs): assert count >= 0 assert reserve >= 0 assert random_state is None or seed is None random_state = get_random_state(random_state, seed) va = self.zeros(count, reserve) va._array[:count] = _create_random_values((count, self.dim), distribution, random_state, **kwargs) return va
def random(self, count=1, distribution='uniform', random_state=None, seed=None, reserve=0, **kwargs): assert count >= 0 assert reserve >= 0 assert random_state is None or seed is None random_state = get_random_state(random_state, seed) va = self.zeros(count, reserve) va._array[:count] = _create_random_values((count, self.dim), distribution, random_state, **kwargs) return va
def random(self, count=1, distribution='uniform', random_state=None, seed=None, reserve=0, **kwargs): assert count >= 0 and reserve >= 0 assert random_state is None or seed is None random_state = get_random_state(random_state, seed) return ListVectorArray([ self.random_vector( distribution=distribution, random_state=random_state, **kwargs) for _ in range(count) ], self)
def random(self, count=1, distribution='uniform', random_state=None, seed=None, reserve=0, **kwargs): """Create a |VectorArray| of vectors with random entries. Supported random distributions:: 'uniform': Uniform distribution in half-open interval [`low`, `high`). 'normal': Normal (Gaussian) distribution with mean `loc` and standard deviation `scale`. Note that not all random distributions are necessarily implemented by all |VectorSpace| implementations. Parameters ---------- count The number of vectors. distribution Random distribution to use (`'uniform'`, `'normal'`). low Lower bound for `'uniform'` distribution (defaults to `0`). high Upper bound for `'uniform'` distribution (defaults to `1`). loc Mean for `'normal'` distribution (defaults to `0`). scale Standard deviation for `'normal'` distribution (defaults to `1`). random_state :class:`~numpy.random.RandomState` to use for sampling. If `None`, a new random state is generated using `seed` as random seed, or the :func:`default <pymor.tools.random.default_random_state>` random state is used. seed If not `None`, a new radom state with this seed is used. reserve Hint for the backend to which length the array will grow. """ assert random_state is None or seed is None random_state = get_random_state(random_state, seed) values = _create_random_values((count, self.dim), distribution, random_state, **kwargs) return self.from_numpy(values)
def random(self, count=1, distribution='uniform', random_state=None, seed=None, reserve=0, **kwargs): """Create a |VectorArray| of vectors with random entries. Supported random distributions:: 'uniform': Uniform distribution in half-open interval [`low`, `high`). 'normal': Normal (Gaussian) distribution with mean `loc` and standard deviation `scale`. Note that not all random distributions are necessarily implemented by all |VectorSpace| implementations. Parameters ---------- count The number of vectors. distribution Random distribution to use (`'uniform'`, `'normal'`). low Lower bound for `'uniform'` distribution (defaults to `0`). high Upper bound for `'uniform'` distribution (defaults to `1`). loc Mean for `'normal'` distribution (defaults to `0`). scale Standard deviation for `'normal'` distribution (defaults to `1`). random_state :class:`~numpy.random.RandomState` to use for sampling. If `None`, a new random state is generated using `seed` as random seed, or the :func:`default <pymor.tools.random.default_random_state>` random state is used. seed If not `None`, a new radom state with this seed is used. reserve Hint for the backend to which length the array will grow. """ assert random_state is None or seed is None random_state = get_random_state(random_state, seed) values = _create_random_values((count, self.dim), distribution, random_state, **kwargs) return self.from_numpy(values)
def random(self, count=1, distribution='uniform', random_state=None, seed=None, reserve=0, **kwargs): assert count >= 0 and reserve >= 0 assert random_state is None or seed is None random_state = get_random_state(random_state, seed) return ListVectorArray([self.random_vector(distribution=distribution, random_state=random_state, **kwargs) for _ in range(count)], self)
def hamiltonian_shifts_init(A, E, B, C, shift_options): """Compute initial shift parameters for low-rank RADI iteration. Compute Galerkin projection of Hamiltonian matrix on space spanned by :math:`C` and return the eigenvalue of the projected Hamiltonian with the most impact on convergence as the next shift parameter. See [BBKS18]_, pp. 318-321. Parameters ---------- A The |Operator| A from the corresponding Riccati equation. E The |Operator| E from the corresponding Riccati equation. B The |VectorArray| B from the corresponding Riccati equation. C The |VectorArray| C from the corresponding Riccati equation. shift_options The shift options to use (see :func:`ricc_lrcf_solver_options`). Returns ------- shifts A |NumPy array| containing a set of stable shift parameters. """ random_state = get_random_state(seed=shift_options['init_seed']) for _ in range(shift_options['init_maxiter']): Q = gram_schmidt(C, atol=0, rtol=0) Ap = A.apply2(Q, Q) QB = Q.dot(B) Gp = QB.dot(QB.T) QR = Q.dot(C) Rp = QR.dot(QR.T) Hp = np.block([[Ap, Gp], [Rp, -Ap.T]]) Ep = E.apply2(Q, Q) EEp = spla.block_diag(Ep, Ep.T) eigvals, eigvecs = spla.eig(Hp, EEp) eigpairs = zip(eigvals, eigvecs) # filter stable eigenvalues eigpairs = list(filter(lambda e: e[0].real < 0, eigpairs)) if len(eigpairs) == 0: # use random subspace instead of span{C} (with same dimensions) C = C.random(len(C), distribution='normal', random_state=random_state) continue # find shift with most impact on convergence maxval = -1 maxind = 0 for i in range(len(eigpairs)): eig = eigpairs[i][1] y_eig = eig[-len(Q):] x_eig = eig[:len(Q)] Ey = Ep.T.dot(y_eig) xEy = np.abs(np.dot(x_eig, Ey)) currval = np.linalg.norm(y_eig)**2 / xEy if currval > maxval: maxval = currval maxind = i shift = eigpairs[maxind][0] # remove imaginary part if it is relatively small if np.abs(shift.imag) / np.abs(shift) < 1e-8: shift = shift.real return np.array([shift]) raise RuntimeError( 'Could not generate initial shifts for low-rank RADI iteration.')