prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Update default training algorithm to support multiple monitoring datasets
  Just follow SGD or BGD for an example
  
  
  </issue>
  <code>
  [start of pylearn2/training_algorithms/default.py]
  1 """
  2 .. todo::
  3 
  4     WRITEME
  5 """
  6 from pylearn2.monitor import Monitor
  7 from pylearn2.training_algorithms.training_algorithm import TrainingAlgorithm
  8 from pylearn2.utils import safe_zip
  9 from pylearn2.utils.data_specs import DataSpecsMapping
  10 import theano.tensor as T
  11 
  12 
  13 class DefaultTrainingAlgorithm(TrainingAlgorithm):
  14     """
  15     .. todo::
  16 
  17         WRITEME
  18     """
  19     def __init__(self, batch_size=None, batches_per_iter=1000,
  20                  monitoring_batches=-1, monitoring_dataset=None,
  21                  termination_criterion=None):
  22         """
  23         Parameters
  24         ----------
  25         batch_size : int
  26             If batch_size is None, reverts to the `force_batch_size` field of \
  27             the model
  28         batches_per_iter : int
  29             WRITEME
  30         monitoring_batches : int
  31             WRITEME
  32         monitoring_dataset : WRITEME
  33         termination_criterion : WRITEME
  34             If specified, can cause the algorithm to terminate before \
  35             `model.learn_batch` says to
  36         """
  37         self.batch_size, self.batches_per_iter = batch_size, batches_per_iter
  38         if monitoring_dataset is None:
  39             assert monitoring_batches == -1
  40         self.monitoring_dataset = monitoring_dataset
  41         self.monitoring_batches = monitoring_batches
  42         self.bSetup = False
  43         self.termination_criterion = termination_criterion
  44 
  45     def setup(self, model, dataset):
  46         """
  47         Allows the training algorithm to do some preliminary configuration
  48         *before* we actually start training the model. The dataset is provided
  49         in case other derived training algorithms need to modify model based on
  50         the dataset.
  51 
  52         Parameters
  53         ----------
  54         model : object
  55             Python object representing the model to train loosely \
  56             implementing the interface of models.model.Model.
  57 
  58         dataset : pylearn2.datasets.dataset.Dataset
  59             Dataset object used to draw training data
  60         """
  61         self.model = model
  62 
  63         self.monitor = Monitor.get_monitor(model)
  64 
  65         if self.monitoring_dataset is not None:
  66             # Get the data specifications needed by the model
  67             space, source = model.get_monitoring_data_specs()
  68 
  69             # Create Theano variables for each of the individual components
  70             # of that data. Usually, it will be X for inputs and Y for targets.
  71             # First, we need to find these components, and put them in a tuple
  72             mapping = DataSpecsMapping((space, source))
  73             space_tuple = mapping.flatten(space, return_tuple=True)
  74             source_tuple = mapping.flatten(source, return_tuple=True)
  75             # Then, build a flat tuple of these Theano variables
  76             ipt = tuple(sp.make_theano_batch(name='monitor_%s' % src)
  77                     for (sp, src) in safe_zip(space_tuple, source_tuple))
  78             # Finally, organize them back into a structure expected by the
  79             # monitoring channels of the model
  80             nested_ipt = mapping.nest(ipt)
  81 
  82             self.monitor.add_dataset(dataset=self.monitoring_dataset,
  83                                 mode="sequential",
  84                                 batch_size=self.batch_size,
  85                                 num_batches=self.monitoring_batches)
  86 
  87             channels = model.get_monitoring_channels(nested_ipt)
  88             if not isinstance(channels, dict):
  89                 raise TypeError("model.get_monitoring_channels must return a "
  90                                 "dictionary, but it returned " + str(channels))
  91             for name in channels:
  92                 J = channels[name]
  93                 if isinstance(J, tuple):
  94                     assert len(J) == 2
  95                     J, prereqs = J
  96                 else:
  97                     prereqs = None
  98 
  99                 self.monitor.add_channel(name=name,
  100                                          ipt=nested_ipt,
  101                                          val=J,
  102                                          prereqs=prereqs,
  103                                          data_specs=(space, source))
  104         self.first = True
  105         self.bSetup = True
  106 
  107     def train(self, dataset):
  108         """
  109         .. todo::
  110 
  111             WRITEME
  112         """
  113         assert self.bSetup
  114         model = self.model
  115         if self.batch_size is None:
  116             batch_size = model.force_batch_size
  117         else:
  118             batch_size = self.batch_size
  119             if hasattr(model, 'force_batch_size'):
  120                 assert (model.force_batch_size <= 0 or batch_size ==
  121                         model.force_batch_size)
  122 
  123         for i in xrange(self.batches_per_iter):
  124             # model.train_batch and self.train both return False when training
  125             # should terminate.
  126             learn_more = model.train_batch(dataset, batch_size)
  127             model.monitor.report_batch(batch_size)
  128             if not learn_more:
  129                 break
  130 
  131         # Make sure we didn't exit training loop because Model.learn
  132         # hasn't been updated to new interface yet.
  133         if learn_more not in [True,False]:
  134             msg = ('The learn method of model %s did not return a boolean ' +
  135                    'value. Please update your model accordingly.')
  136             raise ValueError(msg % str(model))
  137         self.learn_more = learn_more
  138 
  139     def continue_learning(self, model):
  140         """
  141         .. todo::
  142 
  143             WRITEME
  144         """
  145         if self.learn_more:
  146             if self.termination_criterion is not None:
  147                 return self.termination_criterion.continue_learning(model)
  148             return True
  149         return False
  150
  [end of pylearn2/training_algorithms/default.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/pylearn2/training_algorithms/default.py b/pylearn2/training_algorithms/default.py
  --- a/pylearn2/training_algorithms/default.py
  +++ b/pylearn2/training_algorithms/default.py
  @@ -29,7 +29,8 @@
               WRITEME
           monitoring_batches : int
               WRITEME
  -        monitoring_dataset : WRITEME
  +        monitoring_dataset: Dataset or dict
  +            A Dataset or a dictionary mapping string dataset names to Datasets
           termination_criterion : WRITEME
               If specified, can cause the algorithm to terminate before \
               `model.learn_batch` says to
  @@ -37,7 +38,8 @@
           self.batch_size, self.batches_per_iter = batch_size, batches_per_iter
           if monitoring_dataset is None:
               assert monitoring_batches == -1
  -        self.monitoring_dataset = monitoring_dataset
  +
  +        self._set_monitoring_dataset(monitoring_dataset)
           self.monitoring_batches = monitoring_batches
           self.bSetup = False
           self.termination_criterion = termination_criterion
  @@ -74,33 +76,42 @@
               source_tuple = mapping.flatten(source, return_tuple=True)
               # Then, build a flat tuple of these Theano variables
               ipt = tuple(sp.make_theano_batch(name='monitor_%s' % src)
  -                    for (sp, src) in safe_zip(space_tuple, source_tuple))
  +                        for (sp, src) in safe_zip(space_tuple, source_tuple))
               # Finally, organize them back into a structure expected by the
               # monitoring channels of the model
               nested_ipt = mapping.nest(ipt)
   
  -            self.monitor.add_dataset(dataset=self.monitoring_dataset,
  -                                mode="sequential",
  -                                batch_size=self.batch_size,
  -                                num_batches=self.monitoring_batches)
  -
               channels = model.get_monitoring_channels(nested_ipt)
               if not isinstance(channels, dict):
                   raise TypeError("model.get_monitoring_channels must return a "
                                   "dictionary, but it returned " + str(channels))
  -            for name in channels:
  -                J = channels[name]
  -                if isinstance(J, tuple):
  -                    assert len(J) == 2
  -                    J, prereqs = J
  +
  +            for dataset_name in self.monitoring_dataset:
  +                if dataset_name == '':
  +                    prefix = ''
                   else:
  -                    prereqs = None
  +                    prefix = dataset_name + '_'
  +                monitoring_dataset = self.monitoring_dataset[dataset_name]
  +
  +                self.monitor.add_dataset(dataset=monitoring_dataset,
  +                                         mode="sequential",
  +                                         batch_size=self.batch_size)
  +
  +                for name in channels:
  +                    J = channels[name]
  +                    if isinstance(J, tuple):
  +                        assert len(J) == 2
  +                        J, prereqs = J
  +                    else:
  +                        prereqs = None
  +
  +                    self.monitor.add_channel(name=prefix + name,
  +                                             ipt=nested_ipt,
  +                                             val=J,
  +                                             dataset=monitoring_dataset,
  +                                             prereqs=prereqs,
  +                                             data_specs=(space, source))
   
  -                self.monitor.add_channel(name=name,
  -                                         ipt=nested_ipt,
  -                                         val=J,
  -                                         prereqs=prereqs,
  -                                         data_specs=(space, source))
           self.first = True
           self.bSetup = True
   
  @@ -130,7 +141,7 @@
   
           # Make sure we didn't exit training loop because Model.learn
           # hasn't been updated to new interface yet.
  -        if learn_more not in [True,False]:
  +        if learn_more not in [True, False]:
               msg = ('The learn method of model %s did not return a boolean ' +
                      'value. Please update your model accordingly.')
               raise ValueError(msg % str(model))
  
verification_info: {"golden_diff": "diff --git a/pylearn2/training_algorithms/default.py b/pylearn2/training_algorithms/default.py\n--- a/pylearn2/training_algorithms/default.py\n+++ b/pylearn2/training_algorithms/default.py\n@@ -29,7 +29,8 @@\n             WRITEME\n         monitoring_batches : int\n             WRITEME\n-        monitoring_dataset : WRITEME\n+        monitoring_dataset: Dataset or dict\n+            A Dataset or a dictionary mapping string dataset names to Datasets\n         termination_criterion : WRITEME\n             If specified, can cause the algorithm to terminate before \\\n             `model.learn_batch` says to\n@@ -37,7 +38,8 @@\n         self.batch_size, self.batches_per_iter = batch_size, batches_per_iter\n         if monitoring_dataset is None:\n             assert monitoring_batches == -1\n-        self.monitoring_dataset = monitoring_dataset\n+\n+        self._set_monitoring_dataset(monitoring_dataset)\n         self.monitoring_batches = monitoring_batches\n         self.bSetup = False\n         self.termination_criterion = termination_criterion\n@@ -74,33 +76,42 @@\n             source_tuple = mapping.flatten(source, return_tuple=True)\n             # Then, build a flat tuple of these Theano variables\n             ipt = tuple(sp.make_theano_batch(name='monitor_%s' % src)\n-                    for (sp, src) in safe_zip(space_tuple, source_tuple))\n+                        for (sp, src) in safe_zip(space_tuple, source_tuple))\n             # Finally, organize them back into a structure expected by the\n             # monitoring channels of the model\n             nested_ipt = mapping.nest(ipt)\n \n-            self.monitor.add_dataset(dataset=self.monitoring_dataset,\n-                                mode=\"sequential\",\n-                                batch_size=self.batch_size,\n-                                num_batches=self.monitoring_batches)\n-\n             channels = model.get_monitoring_channels(nested_ipt)\n             if not isinstance(channels, dict):\n                 raise TypeError(\"model.get_monitoring_channels must return a \"\n                                 \"dictionary, but it returned \" + str(channels))\n-            for name in channels:\n-                J = channels[name]\n-                if isinstance(J, tuple):\n-                    assert len(J) == 2\n-                    J, prereqs = J\n+\n+            for dataset_name in self.monitoring_dataset:\n+                if dataset_name == '':\n+                    prefix = ''\n                 else:\n-                    prereqs = None\n+                    prefix = dataset_name + '_'\n+                monitoring_dataset = self.monitoring_dataset[dataset_name]\n+\n+                self.monitor.add_dataset(dataset=monitoring_dataset,\n+                                         mode=\"sequential\",\n+                                         batch_size=self.batch_size)\n+\n+                for name in channels:\n+                    J = channels[name]\n+                    if isinstance(J, tuple):\n+                        assert len(J) == 2\n+                        J, prereqs = J\n+                    else:\n+                        prereqs = None\n+\n+                    self.monitor.add_channel(name=prefix + name,\n+                                             ipt=nested_ipt,\n+                                             val=J,\n+                                             dataset=monitoring_dataset,\n+                                             prereqs=prereqs,\n+                                             data_specs=(space, source))\n \n-                self.monitor.add_channel(name=name,\n-                                         ipt=nested_ipt,\n-                                         val=J,\n-                                         prereqs=prereqs,\n-                                         data_specs=(space, source))\n         self.first = True\n         self.bSetup = True\n \n@@ -130,7 +141,7 @@\n \n         # Make sure we didn't exit training loop because Model.learn\n         # hasn't been updated to new interface yet.\n-        if learn_more not in [True,False]:\n+        if learn_more not in [True, False]:\n             msg = ('The learn method of model %s did not return a boolean ' +\n                    'value. Please update your model accordingly.')\n             raise ValueError(msg % str(model))\n", "issue": "Update default training algorithm to support multiple monitoring datasets\nJust follow SGD or BGD for an example\n\n", "before_files": [{"content": "\"\"\"\n.. todo::\n\n    WRITEME\n\"\"\"\nfrom pylearn2.monitor import Monitor\nfrom pylearn2.training_algorithms.training_algorithm import TrainingAlgorithm\nfrom pylearn2.utils import safe_zip\nfrom pylearn2.utils.data_specs import DataSpecsMapping\nimport theano.tensor as T\n\n\nclass DefaultTrainingAlgorithm(TrainingAlgorithm):\n    \"\"\"\n    .. todo::\n\n        WRITEME\n    \"\"\"\n    def __init__(self, batch_size=None, batches_per_iter=1000,\n                 monitoring_batches=-1, monitoring_dataset=None,\n                 termination_criterion=None):\n        \"\"\"\n        Parameters\n        ----------\n        batch_size : int\n            If batch_size is None, reverts to the `force_batch_size` field of \\\n            the model\n        batches_per_iter : int\n            WRITEME\n        monitoring_batches : int\n            WRITEME\n        monitoring_dataset : WRITEME\n        termination_criterion : WRITEME\n            If specified, can cause the algorithm to terminate before \\\n            `model.learn_batch` says to\n        \"\"\"\n        self.batch_size, self.batches_per_iter = batch_size, batches_per_iter\n        if monitoring_dataset is None:\n            assert monitoring_batches == -1\n        self.monitoring_dataset = monitoring_dataset\n        self.monitoring_batches = monitoring_batches\n        self.bSetup = False\n        self.termination_criterion = termination_criterion\n\n    def setup(self, model, dataset):\n        \"\"\"\n        Allows the training algorithm to do some preliminary configuration\n        *before* we actually start training the model. The dataset is provided\n        in case other derived training algorithms need to modify model based on\n        the dataset.\n\n        Parameters\n        ----------\n        model : object\n            Python object representing the model to train loosely \\\n            implementing the interface of models.model.Model.\n\n        dataset : pylearn2.datasets.dataset.Dataset\n            Dataset object used to draw training data\n        \"\"\"\n        self.model = model\n\n        self.monitor = Monitor.get_monitor(model)\n\n        if self.monitoring_dataset is not None:\n            # Get the data specifications needed by the model\n            space, source = model.get_monitoring_data_specs()\n\n            # Create Theano variables for each of the individual components\n            # of that data. Usually, it will be X for inputs and Y for targets.\n            # First, we need to find these components, and put them in a tuple\n            mapping = DataSpecsMapping((space, source))\n            space_tuple = mapping.flatten(space, return_tuple=True)\n            source_tuple = mapping.flatten(source, return_tuple=True)\n            # Then, build a flat tuple of these Theano variables\n            ipt = tuple(sp.make_theano_batch(name='monitor_%s' % src)\n                    for (sp, src) in safe_zip(space_tuple, source_tuple))\n            # Finally, organize them back into a structure expected by the\n            # monitoring channels of the model\n            nested_ipt = mapping.nest(ipt)\n\n            self.monitor.add_dataset(dataset=self.monitoring_dataset,\n                                mode=\"sequential\",\n                                batch_size=self.batch_size,\n                                num_batches=self.monitoring_batches)\n\n            channels = model.get_monitoring_channels(nested_ipt)\n            if not isinstance(channels, dict):\n                raise TypeError(\"model.get_monitoring_channels must return a \"\n                                \"dictionary, but it returned \" + str(channels))\n            for name in channels:\n                J = channels[name]\n                if isinstance(J, tuple):\n                    assert len(J) == 2\n                    J, prereqs = J\n                else:\n                    prereqs = None\n\n                self.monitor.add_channel(name=name,\n                                         ipt=nested_ipt,\n                                         val=J,\n                                         prereqs=prereqs,\n                                         data_specs=(space, source))\n        self.first = True\n        self.bSetup = True\n\n    def train(self, dataset):\n        \"\"\"\n        .. todo::\n\n            WRITEME\n        \"\"\"\n        assert self.bSetup\n        model = self.model\n        if self.batch_size is None:\n            batch_size = model.force_batch_size\n        else:\n            batch_size = self.batch_size\n            if hasattr(model, 'force_batch_size'):\n                assert (model.force_batch_size <= 0 or batch_size ==\n                        model.force_batch_size)\n\n        for i in xrange(self.batches_per_iter):\n            # model.train_batch and self.train both return False when training\n            # should terminate.\n            learn_more = model.train_batch(dataset, batch_size)\n            model.monitor.report_batch(batch_size)\n            if not learn_more:\n                break\n\n        # Make sure we didn't exit training loop because Model.learn\n        # hasn't been updated to new interface yet.\n        if learn_more not in [True,False]:\n            msg = ('The learn method of model %s did not return a boolean ' +\n                   'value. Please update your model accordingly.')\n            raise ValueError(msg % str(model))\n        self.learn_more = learn_more\n\n    def continue_learning(self, model):\n        \"\"\"\n        .. todo::\n\n            WRITEME\n        \"\"\"\n        if self.learn_more:\n            if self.termination_criterion is not None:\n                return self.termination_criterion.continue_learning(model)\n            return True\n        return False\n", "path": "pylearn2/training_algorithms/default.py"}]}