docs: def design(self, max_stimuli=-1, max_inhibitors=-1, max_experiments=10, relax=False, configure=None):
          """
          Finds all optimal experimental designs using up to :attr:`max_experiments` experiments, such that each experiment has
          up to :attr:`max_stimuli` stimuli and :attr:`max_inhibitors` inhibitors. Each optimal experimental design is appended in the
          attribute :attr:`designs` as an instance of :class:`caspo.core.clamping.ClampingList`.
  
          Example::
  
              >>> from caspo import core, design
              >>> networks = core.LogicalNetworkList.from_csv('behaviors.csv')
              >>> setup = core.Setup.from_json('setup.json')
  
              >>> designer = design.Designer(networks, setup)
              >>> designer.design(3, 2)
  
              >>> for i,d in enumerate(designer.designs):
              ...     f = 'design-%s' % i
              ...     d.to_csv(f, stimuli=self.setup.stimuli, inhibitors=self.setup.inhibitors)
  
  
  
          Parameters
          ----------
          max_stimuli : int
              Maximum number of stimuli per experiment
  
          max_inhibitors : int
              Maximum number of inhibitors per experiment
  
          max_experiments : int
              Maximum number of experiments per design
  
          relax : boolean
              Whether to relax the full-pairwise networks discrimination (True) or not (False).
              If relax equals True, the number of experiments per design is fixed to :attr:`max_experiments`
  
          configure : callable
              Callable object responsible of setting clingo configuration
          """
          self.designs = []
  
          args = ['-c maxstimuli=%s' % max_stimuli, '-c maxinhibitors=%s' % max_inhibitors, '-Wno-atom-undefined']
  
          clingo = gringo.Control(args)
          clingo.conf.solve.opt_mode = 'optN'
          if configure is not None:
              configure(clingo.conf)
  
          clingo.add("base", [], self.instance)
          clingo.load(self.encodings['design'])
  
          clingo.ground([("base", [])])
  
          if relax:
              parts = [("step", [step]) for step in xrange(1, max_experiments+1)]
              parts.append(("diff", [max_experiments + 1]))
              clingo.ground(parts)
              ret = clingo.solve(on_model=self.__save__)
          else:
              step, ret = 0, gringo.SolveResult.UNKNOWN
              while step <= max_experiments and ret != gringo.SolveResult.SAT:
                  parts = []
                  parts.append(("check", [step]))
                  if step > 0:
                      clingo.release_external(gringo.Fun("query", [step-1]))
                      parts.append(("step", [step]))
                      clingo.cleanup_domains()
  
                  clingo.ground(parts)
                  clingo.assign_external(gringo.Fun("query", [step]), True)
                  ret, step = clingo.solve(on_model=self.__save__), step + 1
  
          self.stats['time_optimum'] = clingo.stats['time_solve']
          self.stats['time_enumeration'] = clingo.stats['time_total']
  
          self._logger.info("%s optimal experimental designs found in %.4fs", len(self.designs), self.stats['time_enumeration'])