<commit_before>diff -x '*.pyc' -uwr theano-base/theano/compile/function_module.py theano/compile/function_module.py
--- theano-base/theano/compile/function_module.py	2016-02-25 15:15:58.955999947 -0800
+++ theano/compile/function_module.py	2016-02-25 16:30:23.498999147 -0800
@@ -132,11 +132,36 @@
     def __init__(self, protected):
         self.protected = list(protected)
 
+        # # JDEV
+        # print("====================init")
+        # print("\t", list(protected))
+        # print("\n\n")
+
     def validate(self, fgraph):
         if not hasattr(fgraph, 'destroyers'):
             return True
         for r in self.protected + list(fgraph.outputs):
             if fgraph.destroyers(r):
+
+                # # JDEV
+                # if r in fgraph.outputs:
+                #     print("VIOLATION AND IN OUTPUTS!!!!!!!!!")
+                # else:
+                #     print ("VIOLATION AND NOT IN OUTPUTS@@@@@@@@@")
+                #     print (self.protected)
+
+                # JDEV
+                substrs = ["stack_copy", "queue_copy", "aux_stack",
+                           "aux_bwd_stack", "bwd/wrt"]
+                skip = False
+                for substr in substrs:
+                    if substr in str(r):
+                        skip = True
+                        print("SKIP ", r)
+                        break
+                if skip:
+                    continue
+
                 raise gof.InconsistencyError("Trying to destroy a protected"
                                              "Variable.", r)
 
@@ -1063,6 +1088,13 @@
     all_graph_inputs = gof.graph.inputs(fgraph.outputs)
 
     for i in xrange(len(fgraph.outputs)):
+
+        # # JDEV
+        # print(fgraph.outputs[i])
+        # if str(fgraph.outputs[i]) in ["queue_orig", "cursors_orig", "stack_orig", "aux_stack_orig"]: #"AdvancedIncSubtensor" in str(fgraph.outputs[i]):
+        #     print("DEEEP", fgraph.outputs[i])
+        #     continue
+
         views_of_output_i = set()
         view_tree_set(alias_root(fgraph.outputs[i]), views_of_output_i)
         copied = False
@@ -1106,6 +1138,9 @@
                                                 reason="insert_deepcopy")
                             break
                         else:
+                            if "AdvancedIncSubtensor" in str(fgraph.outputs[i]):
+                                print("DEEEP", fgraph.outputs[i])
+                                continue
                             fgraph.change_input(
                                 'output', i,
                                 deep_copy_op(fgraph.outputs[i]),
Only in theano/compile: function_module.py.orig
diff -x '*.pyc' -uwr theano-base/theano/compile/pfunc.py theano/compile/pfunc.py
--- theano-base/theano/compile/pfunc.py	2016-02-25 15:14:41.305999962 -0800
+++ theano/compile/pfunc.py	2016-02-24 14:47:12.173998320 -0800
@@ -174,6 +174,45 @@
                              'input. Consider substituting a non-shared'
                              ' variable via the `givens` parameter') % v)
 
+    def find_path_to(output_var, input_var):
+        """
+        Returns a list of each variable on a (not
+        necessarily unique) path from input_var to
+        output_var, where each variable in the list has
+        the preceding variable as one of its inputs.
+        Returns None if no path exists.
+
+        """
+        # If output and input are the same we have a singleton path
+        if output_var is input_var:
+            return [output_var]
+
+        # If output has no inputs then there is no path
+        owner = output_var.owner
+
+        if owner is None:
+            return None
+
+        # If input_var is an input to the output node, there is a
+        # simple two element path
+        inputs = owner.inputs
+
+        if input_var in inputs:
+            return [input_var, output_var]
+
+        # Otherwise we must recurse by searching for a path to one
+        # of our inputs, then appending the output to that path
+        for ipt in inputs:
+            path = find_path_to(ipt, input_var)
+
+            if path is not None:
+                path.append(output_var)
+
+                return path
+
+        # Since none of the above methods returned a path, there is none
+        return None
+
     # Fill update_d and update_expr with provided updates
     if updates is None:
         updates = []
@@ -182,6 +221,7 @@
             raise TypeError('update target must be a SharedVariable',
                             store_into)
         if store_into in update_d:
+            print(find_path_to(update_d[store_into], store_into))
             raise ValueError('this shared variable already has an update '
                              'expression',
                              (store_into, update_d[store_into]))
Only in theano: generated_version.py
Only in theano/gof: opt.py.orig
Only in theano/gof: opt.py.rej
Only in theano-base/theano/gof: sandbox
diff -x '*.pyc' -uwr theano-base/theano/gradient.py theano/gradient.py
--- theano-base/theano/gradient.py	2016-02-25 15:14:41.434999962 -0800
+++ theano/gradient.py	2016-02-27 20:07:31.618998747 -0800
@@ -361,7 +361,8 @@
 
 def grad(cost, wrt, consider_constant=None,
          disconnected_inputs='raise', add_names=True,
-         known_grads=None, return_disconnected='zero',
+         known_grads=None, grad_overrides=None,
+         return_disconnected='zero',
          null_gradients='raise'):
     """
     Return symbolic gradients for one or more variables with respect to some
@@ -558,7 +559,8 @@
             assert g.type.dtype in tensor.float_dtypes
 
     rval = _populate_grad_dict(var_to_app_to_idx,
-                               grad_dict, wrt, cost_name)
+                               grad_dict, wrt, cost_name,
+                               overrides=grad_overrides)
 
     for i in xrange(len(rval)):
         if isinstance(rval[i].type, NullType):
@@ -932,7 +934,8 @@
 
 
 def _populate_grad_dict(var_to_app_to_idx,
-                        grad_dict, wrt, cost_name=None):
+                        grad_dict, wrt, cost_name=None,
+                        overrides=None):
     """
         Helper function for grad function.
 
@@ -963,6 +966,8 @@
     # its inputs' gradients
     term_dict = OrderedDict()
 
+    overrides = overrides or {}
+
     def access_term_cache(node):
         """ Populates term_dict[node] and returns it """
 
@@ -1110,6 +1115,9 @@
                                 str(o_shape) + " on an output of shape " +
                                 str(g_shape))
 
+                if node.op.__class__ in overrides:
+                    input_grads = overrides[node.op.__class__](node.op, inputs, new_output_grads)
+                else:
                 input_grads = node.op.grad(inputs, new_output_grads)
 
                 if input_grads is None:
@@ -1292,11 +1300,11 @@
                         if isinstance(term.type, DisconnectedType):
                             continue
 
-                        if hasattr(var, 'ndim') and term.ndim != var.ndim:
-                            raise ValueError(
-                                ("%s.grad returned a term with"
-                                 " %d dimensions, but %d are required.") % (
-                                     str(node.op), term.ndim, var.ndim))
+                        # if hasattr(var, 'ndim') and term.ndim != var.ndim:
+                        #     raise ValueError(
+                        #         ("%s.grad returned a term with"
+                        #          " %d dimensions, but %d are required.") % (
+                        #              str(node.op), term.ndim, var.ndim))
 
                         terms.append(term)
 
@@ -1318,6 +1326,7 @@
                 # this variable isn't connected to the cost in the<commit_msg>Add documentation to Theano gradient.py to make it clear exactly how hacky this is<commit_after>diff -x '*.pyc' -uwr theano-base/theano/compile/function_module.py theano/compile/function_module.py
--- theano-base/theano/compile/function_module.py	2016-02-25 15:15:58.955999947 -0800
+++ theano/compile/function_module.py	2016-02-25 16:30:23.498999147 -0800
@@ -132,11 +132,36 @@
     def __init__(self, protected):
         self.protected = list(protected)
 
+        # # JDEV
+        # print("====================init")
+        # print("\t", list(protected))
+        # print("\n\n")
+
     def validate(self, fgraph):
         if not hasattr(fgraph, 'destroyers'):
             return True
         for r in self.protected + list(fgraph.outputs):
             if fgraph.destroyers(r):
+
+                # # JDEV
+                # if r in fgraph.outputs:
+                #     print("VIOLATION AND IN OUTPUTS!!!!!!!!!")
+                # else:
+                #     print ("VIOLATION AND NOT IN OUTPUTS@@@@@@@@@")
+                #     print (self.protected)
+
+                # JDEV
+                substrs = ["stack_copy", "queue_copy", "aux_stack",
+                           "aux_bwd_stack", "bwd/wrt"]
+                skip = False
+                for substr in substrs:
+                    if substr in str(r):
+                        skip = True
+                        print("SKIP ", r)
+                        break
+                if skip:
+                    continue
+
                 raise gof.InconsistencyError("Trying to destroy a protected"
                                              "Variable.", r)
 
@@ -1063,6 +1088,13 @@
     all_graph_inputs = gof.graph.inputs(fgraph.outputs)
 
     for i in xrange(len(fgraph.outputs)):
+
+        # # JDEV
+        # print(fgraph.outputs[i])
+        # if str(fgraph.outputs[i]) in ["queue_orig", "cursors_orig", "stack_orig", "aux_stack_orig"]: #"AdvancedIncSubtensor" in str(fgraph.outputs[i]):
+        #     print("DEEEP", fgraph.outputs[i])
+        #     continue
+
         views_of_output_i = set()
         view_tree_set(alias_root(fgraph.outputs[i]), views_of_output_i)
         copied = False
@@ -1106,6 +1138,9 @@
                                                 reason="insert_deepcopy")
                             break
                         else:
+                            if "AdvancedIncSubtensor" in str(fgraph.outputs[i]):
+                                print("DEEEP", fgraph.outputs[i])
+                                continue
                             fgraph.change_input(
                                 'output', i,
                                 deep_copy_op(fgraph.outputs[i]),
Only in theano/compile: function_module.py.orig
diff -x '*.pyc' -uwr theano-base/theano/compile/pfunc.py theano/compile/pfunc.py
--- theano-base/theano/compile/pfunc.py	2016-02-25 15:14:41.305999962 -0800
+++ theano/compile/pfunc.py	2016-02-24 14:47:12.173998320 -0800
@@ -174,6 +174,45 @@
                              'input. Consider substituting a non-shared'
                              ' variable via the `givens` parameter') % v)
 
+    def find_path_to(output_var, input_var):
+        """
+        Returns a list of each variable on a (not
+        necessarily unique) path from input_var to
+        output_var, where each variable in the list has
+        the preceding variable as one of its inputs.
+        Returns None if no path exists.
+
+        """
+        # If output and input are the same we have a singleton path
+        if output_var is input_var:
+            return [output_var]
+
+        # If output has no inputs then there is no path
+        owner = output_var.owner
+
+        if owner is None:
+            return None
+
+        # If input_var is an input to the output node, there is a
+        # simple two element path
+        inputs = owner.inputs
+
+        if input_var in inputs:
+            return [input_var, output_var]
+
+        # Otherwise we must recurse by searching for a path to one
+        # of our inputs, then appending the output to that path
+        for ipt in inputs:
+            path = find_path_to(ipt, input_var)
+
+            if path is not None:
+                path.append(output_var)
+
+                return path
+
+        # Since none of the above methods returned a path, there is none
+        return None
+
     # Fill update_d and update_expr with provided updates
     if updates is None:
         updates = []
@@ -182,6 +221,7 @@
             raise TypeError('update target must be a SharedVariable',
                             store_into)
         if store_into in update_d:
+            print(find_path_to(update_d[store_into], store_into))
             raise ValueError('this shared variable already has an update '
                              'expression',
                              (store_into, update_d[store_into]))
Only in theano: generated_version.py
Only in theano/gof: opt.py.orig
Only in theano/gof: opt.py.rej
Only in theano-base/theano/gof: sandbox
diff -x '*.pyc' -uwr theano-base/theano/gradient.py theano/gradient.py
--- theano-base/theano/gradient.py	2016-02-25 15:14:41.434999962 -0800
+++ theano/gradient.py	2016-02-27 20:10:36.933998714 -0800
@@ -361,7 +361,8 @@
 
 def grad(cost, wrt, consider_constant=None,
          disconnected_inputs='raise', add_names=True,
-         known_grads=None, return_disconnected='zero',
+         known_grads=None, grad_overrides=None,
+         return_disconnected='zero',
          null_gradients='raise'):
     """
     Return symbolic gradients for one or more variables with respect to some
@@ -558,7 +559,8 @@
             assert g.type.dtype in tensor.float_dtypes
 
     rval = _populate_grad_dict(var_to_app_to_idx,
-                               grad_dict, wrt, cost_name)
+                               grad_dict, wrt, cost_name,
+                               overrides=grad_overrides)
 
     for i in xrange(len(rval)):
         if isinstance(rval[i].type, NullType):
@@ -932,7 +934,8 @@
 
 
 def _populate_grad_dict(var_to_app_to_idx,
-                        grad_dict, wrt, cost_name=None):
+                        grad_dict, wrt, cost_name=None,
+                        overrides=None):
     """
         Helper function for grad function.
 
@@ -963,6 +966,8 @@
     # its inputs' gradients
     term_dict = OrderedDict()
 
+    overrides = overrides or {}
+
     def access_term_cache(node):
         """ Populates term_dict[node] and returns it """
 
@@ -1110,6 +1115,9 @@
                                 str(o_shape) + " on an output of shape " +
                                 str(g_shape))
 
+                if node.op.__class__ in overrides:
+                    input_grads = overrides[node.op.__class__](node.op, inputs, new_output_grads)
+                else:
                 input_grads = node.op.grad(inputs, new_output_grads)
 
                 if input_grads is None:
@@ -1292,11 +1300,17 @@
                         if isinstance(term.type, DisconnectedType):
                             continue
 
-                        if hasattr(var, 'ndim') and term.ndim != var.ndim:
-                            raise ValueError(
-                                ("%s.grad returned a term with"
-                                 " %d dimensions, but %d are required.") % (
-                                     str(node.op), term.ndim, var.ndim))
+                        # JDEV: Let gradient ops change output ndim.
+                        # This is required in order to support Jacobian outputs
+                        # when hacky Jacobian overrides are passed. It would be
+                        # cleaner to make a "fork" of this function and its
+                        # dependents which is explicitly a Jacobian function.
+                        #
+                        # if hasattr(var, 'ndim') and term.ndim != var.ndim:
+                        #     raise ValueError(
+                        #         ("%s.grad returned a term with"
+                        #          " %d dimensions, but %d are required.") % (
+                        #              str(node.op), term.ndim, var.ndim))
 
                         terms.append(term)
 
@@ -1318,6 +1332,7 @@
                 # this variable isn't connected to the cost in the
{'fraction_non_alphanumeric': 0.11018415523421085, 'fraction_numerical': 0.033864788036089485, 'mean_word_length': 1.537315772969583, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2520843', 'n_tokens_mistral': 5124, 'n_tokens_neox': 4622, 'n_words': 1168}