def __init__(self, **kwargs): """Initializes a model. kwargs: `r_mat` must be a square matrix (list of lists of floats). Diagonal elements will be ignored. The columns of this matrix will be multiplied by their corresponding equilibirium frequencies. `r_upper` can be used instead of `r_mat.` It should correspond to the upper triangle of the R-matrix. `equil_freq` must be None a list of the equilibrium frequencies. """ r_upper = kwargs.get('r_upper') r_mat = kwargs.get('r_mat') sf = kwargs.get('state_freq') self.normalize_rates = kwargs.get('normalize_rates', True) # adjust the qmat such that the mean flux is 1.0 if r_upper: if r_mat: raise ValueError("r_mat or r_upper cannot both be specified") r_mat = _r_upper_to_r_mat(r_upper) _LOG.debug('r_mat from r_upper (%s) is %s' % (str(r_upper), str(r_mat))) elif not r_mat: raise ValueError("Either r_mat or r_upper must be given") priv_mat = [] param_set = set() for row in r_mat: priv_row = list(row) for n, cell in enumerate(row): try: param_set.update(cell.parameters()) except: priv_row[n] = MutableFloatParameter(cell) priv_mat.append(tuple(priv_row)) if sf is None: raise ValueError("State frequencies must be specified for a RevDiscStateContTimeModel") if isinstance(sf, ProbabilityVectorParameter): self._state_freq = sf else: priv_sf = list(sf) for cell in sf: try: param_set.update(cell.parameters()) priv_sf.append(cell) except: priv_sf.append(FloatParameter(cell)) self._state_freq = ProbabilityVectorParameter(priv_sf) param_set.update(set(self._state_freq.parameters())) DiscStateContTimeModel.__init__(self, param_list=param_set, **kwargs) if r_mat: if self.num_states is None: self._num_states = len(r_mat) self._verify_r_mat(r_mat) else: raise ValueError("Either r_mat or r_upper must be specified") self._r_mat = tuple(priv_mat)
class RevDiscStateContTimeModel(DiscStateContTimeModel): def __init__(self, **kwargs): """Initializes a model. kwargs: `r_mat` must be a square matrix (list of lists of floats). Diagonal elements will be ignored. The columns of this matrix will be multiplied by their corresponding equilibirium frequencies. `r_upper` can be used instead of `r_mat.` It should correspond to the upper triangle of the R-matrix. `equil_freq` must be None a list of the equilibrium frequencies. """ r_upper = kwargs.get('r_upper') r_mat = kwargs.get('r_mat') sf = kwargs.get('state_freq') self.normalize_rates = kwargs.get('normalize_rates', True) # adjust the qmat such that the mean flux is 1.0 if r_upper: if r_mat: raise ValueError("r_mat or r_upper cannot both be specified") r_mat = _r_upper_to_r_mat(r_upper) _LOG.debug('r_mat from r_upper (%s) is %s' % (str(r_upper), str(r_mat))) elif not r_mat: raise ValueError("Either r_mat or r_upper must be given") priv_mat = [] param_set = set() for row in r_mat: priv_row = list(row) for n, cell in enumerate(row): try: param_set.update(cell.parameters()) except: priv_row[n] = MutableFloatParameter(cell) priv_mat.append(tuple(priv_row)) if sf is None: raise ValueError("State frequencies must be specified for a RevDiscStateContTimeModel") if isinstance(sf, ProbabilityVectorParameter): self._state_freq = sf else: priv_sf = list(sf) for cell in sf: try: param_set.update(cell.parameters()) priv_sf.append(cell) except: priv_sf.append(FloatParameter(cell)) self._state_freq = ProbabilityVectorParameter(priv_sf) param_set.update(set(self._state_freq.parameters())) DiscStateContTimeModel.__init__(self, param_list=param_set, **kwargs) if r_mat: if self.num_states is None: self._num_states = len(r_mat) self._verify_r_mat(r_mat) else: raise ValueError("Either r_mat or r_upper must be specified") self._r_mat = tuple(priv_mat) def get_r_mat(self): "Accessor for R-matrix." return self._r_mat r_mat = property(get_r_mat) def get_r_upper(self): "Accessor for R-matrix." return _r_mat_to_r_upper(self._r_mat) r_upper = property(get_r_upper) def get_state_freq(self): "Accessor for state frequencies." return self._state_freq def set_state_freq(self, v): "Accessor for state frequencies." _LOG.debug("In RevDiscStateContTimeModel.set_state_freq") if isinstance(v, ProbabilityVectorParameter): self.substitute_parameter_instance(self._state_freq, v) self._state_freq = v else: self._state_freq.value = v state_freq = property(get_state_freq, set_state_freq) q_mat = property(DiscStateContTimeModel.get_q_mat) def calc_q_mat(self): """Uses self._state_freq and self._r_mat to refresh self._q_mat. As required by the current version of cdsctm_set_q_mat, the Q-matrix is rescaled such that each row sums to 0.0 and the weighted average of the diagonal elements is -1.0 (with the weight being the associated equilibrium frequency).""" assert(self._state_freq is not None) _LOG.debug("in self.calc_q_mat: _r_mat = %s _state_freq = %s" % (repr(self._r_mat), str(self._state_freq))) ns = self.num_states qr = [0.0] * ns qm = [list(qr) for i in range(ns)] w_mat_sum = 0.0 for i, rows in enumerate(izip(self._r_mat, self._state_freq)): r_row, sf = rows q_row = qm[i] row_sum = 0.0 for j, to_state in enumerate(izip(r_row, self._state_freq)): r_val, stf = [float(p) for p in to_state] if i != j: v = r_val * stf assert(r_val >= 0.0) assert(stf >= 0.0) q_row[j] = v row_sum += v q_row[i] = -row_sum w_mat_sum += row_sum*self._state_freq[i] if self.normalize_rates: for q_row in qm: for i in xrange(len(q_row)): q_row[i] /= w_mat_sum self._q_mat = tuple([tuple(row) for row in qm]) _LOG.debug("_q_mat = %s" % str(qm)) return self._q_mat def _verify_eq_freq_len(self, equil_freq): "Raises a ValueError if `equil_freq` is not the correct length" nef = len(equil_freq) if nef != self._num_states: if nef != (1 + self._num_states): raise ValueError("The number of states in the r_mat and "\ "equil_freq must agree.") def _verify_r_mat(self, r_mat): """Raises a ValueError if `r_mat` is not the correct shape or has negative values (other than on the diagonal). """ for i, row in enumerate(r_mat): if len(row) != self.num_states: raise ValueError("The R-matrix must be square.") for j, val in enumerate(row): if i != j: if val < 0.0: raise ValueError("Off-diagonal elements of the "\ "R-matrix cannot be negative.") if abs(val - float(r_mat[j][i])) > 1.0e-6: raise ValueError("R-matrix must be symmetric") def get_num_states(self): "Returns the number of states" return self._num_states def get_adjusted_brlens_list(self, b): return [b] def get_model_list(self): return [self] def get_model_probs(self): return (1.0,) def get_parameters(self): return self._parameters model_probs = property(get_model_probs) r_mat = property(get_r_mat) r_upper = property(get_r_upper) def get_state_freq_value(self): return self._state_freq.value def set_state_freq_value(self, v): self._state_freq.value = v state_freq_value = property(get_state_freq_value, set_state_freq_value)