docs: def evaluate(self, artifact):
          r"""Evaluate artifact with agent's current rules and weights.
  
          :param artifact:
              :class:`~creamas.core.artifact.Artifact` to be evaluated
  
          :type artifact:
              :py:class:`~creamas.core.artifact.Artifact`
  
          :returns:
              Agent's evaluation of the artifact, in [-1,1], and framing. In this
              basic implementation framing is always ``None``.
  
          :rtype:
              tuple
  
          Actual evaluation formula in this basic implementation is:
  
          .. math::
  
              e(A) = \frac{\sum_{i=1}^{n} r_{i}(A)w_i}
              {\sum_{i=1}^{n} \lvert w_i \rvert},
  
          where :math:`r_{i}(A)` is the :math:`i` th rule's evaluation on
          artifact :math:`A`, and :math:`w_i` is the weight for rule
          :math:`r_i`.
          """
          s = 0
          w = 0.0
          if len(self.R) == 0:
              return 0.0, None
  
          for i in range(len(self.R)):
              s += self.R[i](artifact) * self.W[i]
              w += abs(self.W[i])
  
          if w == 0.0:
              return 0.0, None
          return s / w, None