From 62dd68e19961d6585d96544cb724fa49270ffe3c Mon Sep 17 00:00:00 2001 From: Raffi Khatchadourian Date: Mon, 4 Mar 2024 11:19:18 -0500 Subject: [PATCH 1/8] Test updates. --- .../HybridizeFunctionRefactoringTest.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java b/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java index 52b4a9f9..4a889c18 100644 --- a/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java +++ b/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java @@ -4686,7 +4686,7 @@ public void testModel3() throws Exception { break; case "call": assertTrue("Expecting " + simpleName + " to have a tensor param.", f.getLikelyHasTensorParameter()); - assertTrue("Should pass preconditions.", f.getStatus().isOK()); + assertFalse("Should pass preconditions.", f.getStatus().hasError()); assertFalse("No Python side-effects.", f.getHasPythonSideEffects()); break; default: @@ -4728,7 +4728,7 @@ public void testModel4() throws Exception { break; case "__call__": assertTrue("Expecting " + simpleName + " to have a tensor param.", f.getLikelyHasTensorParameter()); - assertTrue("Should pass preconditions.", f.getStatus().isOK()); + assertFalse("Should pass preconditions.", f.getStatus().hasError()); assertFalse("No Python side-effects.", f.getHasPythonSideEffects()); break; default: @@ -4876,7 +4876,7 @@ private void testPreconditionCheckingHelper(boolean expectedHybrid, boolean expe assertEquals(expectedTransformation, transformation); assertEquals(precondition, function.getPassingPrecondition()); - assertTrue(function.getStatus().isOK()); + assertFalse(function.getStatus().hasError()); } @Test @@ -5394,7 +5394,7 @@ public void testPythonSideEffects44() throws Exception { assertTrue(function.getLikelyHasTensorParameter()); assertFalse(function.getHasPythonSideEffects()); - assertTrue(function.getStatus().isOK()); + assertFalse(function.getStatus().hasError()); assertTrue(function.getRefactoring() == Refactoring.CONVERT_EAGER_FUNCTION_TO_HYBRID); assertTrue(function.getPassingPrecondition() == PreconditionSuccess.P1); assertEquals(Collections.singleton(Transformation.CONVERT_TO_HYBRID), function.getTransformations()); @@ -5502,7 +5502,7 @@ public void testPythonSideEffects48() throws Exception { assertFalse(capturesLeakedTensor.getHasPythonSideEffects()); // NOTE: Change to assertFalse once https://github.com/ponder-lab/Hybridize-Functions-Refactoring/issues/281 is fixed. - assertTrue("Passes P1.", capturesLeakedTensor.getStatus().isOK()); + assertFalse("Passes P1.", capturesLeakedTensor.getStatus().hasError()); assertFalse(capturesLeakedTensor.getStatus().hasWarning()); // NOTE: Change to assertTrue once https://github.com/ponder-lab/Hybridize-Functions-Refactoring/issues/281 is fixed. @@ -5615,7 +5615,7 @@ public void testPythonSideEffects54() throws Exception { RefactoringStatus status = function.getStatus(); assertTrue("We can't convert something to eager if it has side-effects because that will alter semantics.", status.hasError()); - assertEquals(2, status.getEntries().length); + assertEquals(2, Arrays.stream(status.getEntries()).filter(e -> !e.isInfo()).count()); assertEquals(PreconditionFailure.HAS_PYTHON_SIDE_EFFECTS.getCode(), status.getEntryWithHighestSeverity().getCode()); assertEquals(Refactoring.OPTIMIZE_HYBRID_FUNCTION, function.getRefactoring()); @@ -5634,7 +5634,7 @@ public void testPythonSideEffects55() throws Exception { RefactoringStatus status = function.getStatus(); assertFalse("We can convert something to eager if it does not have side-effects because that will not alter semantics.", status.hasError()); - assertEquals(0, status.getEntries().length); + assertEquals(0, Arrays.stream(status.getEntries()).filter(RefactoringStatusEntry::isError).count()); assertEquals(Refactoring.OPTIMIZE_HYBRID_FUNCTION, function.getRefactoring()); assertNotNull(function.getPassingPrecondition()); @@ -5817,7 +5817,7 @@ public void testRecursion2() throws Exception { assertFalse(f.getIsRecursive()); // F. assertNull(f.getEntryMatchingFailure(PreconditionFailure.IS_RECURSIVE)); - assertTrue(f.getStatus().isOK()); + assertFalse(f.getStatus().hasError()); assertEquals(P1, f.getPassingPrecondition()); assertEquals(Collections.singleton(CONVERT_TO_HYBRID), f.getTransformations()); } @@ -6256,7 +6256,7 @@ public void testTensorFlowEagerExecution() throws Exception { assertEquals(P1, f.getPassingPrecondition()); assertEquals(CONVERT_EAGER_FUNCTION_TO_HYBRID, f.getRefactoring()); assertTrue(f.getErrors().isEmpty()); - assertTrue(f.getStatus().isOK()); + assertFalse(f.getStatus().hasError()); assertEquals(singleton(CONVERT_TO_HYBRID), f.getTransformations()); f = getFunction("train_step"); @@ -6377,7 +6377,7 @@ public void testNeuralNetwork() throws Exception { case "cross_entropy_loss": case "NeuralNet.call": testFunction(function, false, true, false, false, false, CONVERT_EAGER_FUNCTION_TO_HYBRID, P1, singleton(CONVERT_TO_HYBRID), - RefactoringStatus.OK); + RefactoringStatus.INFO); break; case "NeuralNet.__init__": assertFalse(function.getStatus().isOK()); @@ -6399,7 +6399,7 @@ public void testAutoEncoder() throws Exception { case "run_optimization": case "decoder": testFunction(function, false, true, false, false, false, CONVERT_EAGER_FUNCTION_TO_HYBRID, P1, singleton(CONVERT_TO_HYBRID), - RefactoringStatus.OK); + RefactoringStatus.INFO); break; default: throw new IllegalStateException("Not expecting: " + function.getIdentifier() + "."); From 081502a9860bfe36fba388cb9a7bd7a8936223fa Mon Sep 17 00:00:00 2001 From: Raffi Khatchadourian Date: Mon, 4 Mar 2024 17:46:37 -0500 Subject: [PATCH 2/8] Add keras model attributes. --- edu.cuny.hunter.hybridize.core/tensorflow.xml | 41 ++++++++++++++++ .../HybridizeFunction/testModel10/in/A.py | 17 +++++++ .../testModel10/in/requirements.txt | 1 + .../HybridizeFunction/testModel11/in/A.py | 16 +++++++ .../testModel11/in/requirements.txt | 1 + .../HybridizeFunction/testModel12/in/A.py | 17 +++++++ .../testModel12/in/requirements.txt | 1 + .../HybridizeFunction/testModel13/in/A.py | 16 +++++++ .../testModel13/in/requirements.txt | 1 + .../HybridizeFunction/testModel8/in/A.py | 15 ++++++ .../testModel8/in/requirements.txt | 1 + .../HybridizeFunction/testModel9/in/A.py | 16 +++++++ .../testModel9/in/requirements.txt | 1 + .../HybridizeFunctionRefactoringTest.java | 48 +++++++++++++++++++ hybridize.target | 2 +- 15 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel10/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel10/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel11/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel11/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel12/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel12/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel13/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel13/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel8/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel8/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel9/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel9/in/requirements.txt diff --git a/edu.cuny.hunter.hybridize.core/tensorflow.xml b/edu.cuny.hunter.hybridize.core/tensorflow.xml index 20e381d1..ddcda65b 100644 --- a/edu.cuny.hunter.hybridize.core/tensorflow.xml +++ b/edu.cuny.hunter.hybridize.core/tensorflow.xml @@ -45,6 +45,8 @@ + + @@ -146,6 +148,9 @@ + + + @@ -729,6 +734,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel10/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel10/in/A.py new file mode 100644 index 00000000..86b2c84b --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel10/in/A.py @@ -0,0 +1,17 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +def f(a): + pass + + +inputs = tf.keras.Input(shape=(3,)) +x = tf.keras.layers.Dense(4, activation=tf.nn.relu)(inputs) +outputs = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x) +model = tf.keras.Model(inputs=inputs, outputs=outputs) + +# From https://www.tensorflow.org/guide/keras/transfer_learning#freezing_layers_understanding_the_trainable_attribute +for i in model.weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel10/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel10/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel10/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel11/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel11/in/A.py new file mode 100644 index 00000000..800b85c7 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel11/in/A.py @@ -0,0 +1,16 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +def f(a): + pass + + +a = tf.keras.layers.Input(shape=(64,)) +b = tf.keras.layers.Dense(5)(a) +model = tf.keras.models.Model(a, b) + +# From https://www.tensorflow.org/guide/keras/transfer_learning#freezing_layers_understanding_the_trainable_attribute. +for i in model.weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel11/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel11/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel11/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel12/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel12/in/A.py new file mode 100644 index 00000000..71cda261 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel12/in/A.py @@ -0,0 +1,17 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +def f(a): + pass + + +inputs = tf.keras.Input(shape=(3,)) +x = tf.keras.layers.Dense(4, activation=tf.nn.relu)(inputs) +outputs = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x) +model = tf.keras.Model(inputs=inputs, outputs=outputs) + +# From https://www.tensorflow.org/guide/keras/transfer_learning#freezing_layers_understanding_the_trainable_attribute +for i in model.non_trainable_weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel12/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel12/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel12/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel13/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel13/in/A.py new file mode 100644 index 00000000..d44ff1c5 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel13/in/A.py @@ -0,0 +1,16 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +def f(a): + pass + + +a = tf.keras.layers.Input(shape=(64,)) +b = tf.keras.layers.Dense(5)(a) +model = tf.keras.models.Model(a, b) + +# From https://www.tensorflow.org/guide/keras/transfer_learning#freezing_layers_understanding_the_trainable_attribute. +for i in model.non_trainable_weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel13/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel13/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel13/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel8/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel8/in/A.py new file mode 100644 index 00000000..19848e16 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel8/in/A.py @@ -0,0 +1,15 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +def f(a): + pass + + +a = tf.keras.layers.Input(shape=(64,)) +b = tf.keras.layers.Dense(5)(a) +model = tf.keras.models.Model(a, b) + +for i in model.trainable_weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel8/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel8/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel8/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel9/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel9/in/A.py new file mode 100644 index 00000000..65348e9e --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel9/in/A.py @@ -0,0 +1,16 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +def f(a): + pass + + +inputs = tf.keras.Input(shape=(3,)) +x = tf.keras.layers.Dense(4, activation=tf.nn.relu)(inputs) +outputs = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x) +model = tf.keras.Model(inputs=inputs, outputs=outputs) + +for i in model.trainable_weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel9/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel9/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel9/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java b/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java index 4a889c18..26176ce3 100644 --- a/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java +++ b/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java @@ -4852,6 +4852,54 @@ public void testModel7() throws Exception { }); } + @Test + public void testModel8() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + } + + @Test + public void testModel9() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + } + + @Test + public void testModel10() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + } + + @Test + public void testModel11() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + } + + @Test + public void testModel12() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + } + + @Test + public void testModel13() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + } + // TODO: Test models that have tf.functions. private void testPreconditionCheckingHelper(boolean expectedHybrid, boolean expectedTensorParameter, Refactoring expectedRefactoring, diff --git a/hybridize.target b/hybridize.target index 4feb74c1..b8b1985f 100644 --- a/hybridize.target +++ b/hybridize.target @@ -53,4 +53,4 @@ -Declipse.p2.max.threads=10 -Doomph.update.url=https://download.eclipse.org/oomph/updates/milestone/latest -Doomph.redirection.index.redirection=index:/->http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/ -Dosgi.requiredJavaVersion=17 -Dosgi.instance.area.default=@user.home/eclipse-workspace -Dosgi.dataAreaRequiresExplicitInit=true -Dorg.eclipse.swt.graphics.Resource.reportNonDisposed=true -Dsun.java.command=Eclipse -XX:+UseG1GC -XX:+UseStringDeduplication --add-modules=ALL-SYSTEM -Dosgi.requiredJavaVersion=11 -Dosgi.dataAreaRequiresExplicitInit=true -Dorg.eclipse.swt.graphics.Resource.reportNonDisposed=true -Xms256m -Xmx2048m --add-modules=ALL-SYSTEM - + \ No newline at end of file From 7353724eaf84d618b5b41b414836eb108a50cfa3 Mon Sep 17 00:00:00 2001 From: Raffi Khatchadourian Date: Mon, 4 Mar 2024 18:06:00 -0500 Subject: [PATCH 3/8] More tests. --- .../HybridizeFunction/testModel14/in/A.py | 17 ++++++ .../testModel14/in/requirements.txt | 1 + .../HybridizeFunction/testModel15/in/A.py | 18 ++++++ .../testModel15/in/requirements.txt | 1 + .../HybridizeFunction/testModel16/in/A.py | 16 +++++ .../testModel16/in/requirements.txt | 1 + .../HybridizeFunction/testModel17/in/A.py | 17 ++++++ .../testModel17/in/requirements.txt | 1 + .../HybridizeFunction/testModel18/in/A.py | 18 ++++++ .../testModel18/in/requirements.txt | 1 + .../HybridizeFunction/testModel19/in/A.py | 17 ++++++ .../testModel19/in/requirements.txt | 1 + .../HybridizeFunctionRefactoringTest.java | 60 +++++++++++++++++++ 13 files changed, 169 insertions(+) create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel14/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel14/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel15/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel15/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel16/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel16/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel17/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel17/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel18/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel18/in/requirements.txt create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel19/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel19/in/requirements.txt diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel14/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel14/in/A.py new file mode 100644 index 00000000..0d78db08 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel14/in/A.py @@ -0,0 +1,17 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +@tf.function() +def f(a): + pass + + +a = tf.keras.layers.Input(shape=(64,)) +b = tf.keras.layers.Dense(5)(a) +model = tf.keras.models.Model(a, b) + +# From https://www.tensorflow.org/guide/keras/transfer_learning#freezing_layers_understanding_the_trainable_attribute. +for i in model.weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel14/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel14/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel14/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel15/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel15/in/A.py new file mode 100644 index 00000000..01049e91 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel15/in/A.py @@ -0,0 +1,18 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +@tf.function() +def f(a): + pass + + +inputs = tf.keras.Input(shape=(3,)) +x = tf.keras.layers.Dense(4, activation=tf.nn.relu)(inputs) +outputs = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x) +model = tf.keras.Model(inputs=inputs, outputs=outputs) + +# From https://www.tensorflow.org/guide/keras/transfer_learning#freezing_layers_understanding_the_trainable_attribute +for i in model.weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel15/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel15/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel15/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel16/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel16/in/A.py new file mode 100644 index 00000000..5d6fa6e9 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel16/in/A.py @@ -0,0 +1,16 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +@tf.function() +def f(a): + pass + + +a = tf.keras.layers.Input(shape=(64,)) +b = tf.keras.layers.Dense(5)(a) +model = tf.keras.models.Model(a, b) + +for i in model.trainable_weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel16/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel16/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel16/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel17/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel17/in/A.py new file mode 100644 index 00000000..4cb4b28a --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel17/in/A.py @@ -0,0 +1,17 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +@tf.function() +def f(a): + pass + + +a = tf.keras.layers.Input(shape=(64,)) +b = tf.keras.layers.Dense(5)(a) +model = tf.keras.models.Model(a, b) + +# From https://www.tensorflow.org/guide/keras/transfer_learning#freezing_layers_understanding_the_trainable_attribute. +for i in model.non_trainable_weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel17/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel17/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel17/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel18/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel18/in/A.py new file mode 100644 index 00000000..114a7043 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel18/in/A.py @@ -0,0 +1,18 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +@tf.function() +def f(a): + pass + + +inputs = tf.keras.Input(shape=(3,)) +x = tf.keras.layers.Dense(4, activation=tf.nn.relu)(inputs) +outputs = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x) +model = tf.keras.Model(inputs=inputs, outputs=outputs) + +# From https://www.tensorflow.org/guide/keras/transfer_learning#freezing_layers_understanding_the_trainable_attribute +for i in model.non_trainable_weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel18/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel18/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel18/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel19/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel19/in/A.py new file mode 100644 index 00000000..f5cef470 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel19/in/A.py @@ -0,0 +1,17 @@ +# From https://github.com/tensorflow/tensorflow/issues/14359#issue-272179775 + +import tensorflow as tf + + +@tf.function() +def f(a): + pass + + +inputs = tf.keras.Input(shape=(3,)) +x = tf.keras.layers.Dense(4, activation=tf.nn.relu)(inputs) +outputs = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x) +model = tf.keras.Model(inputs=inputs, outputs=outputs) + +for i in model.trainable_weights: + f(i) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel19/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel19/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testModel19/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java b/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java index 26176ce3..6da33f52 100644 --- a/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java +++ b/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java @@ -4858,6 +4858,7 @@ public void testModel8() throws Exception { assertTrue(function.getLikelyHasTensorParameter()); assertFalse(function.getLikelyHasPrimitiveParameters()); assertFalse(function.getHasPythonSideEffects()); + assertFalse(function.getIsHybrid()); } @Test @@ -4866,6 +4867,7 @@ public void testModel9() throws Exception { assertTrue(function.getLikelyHasTensorParameter()); assertFalse(function.getLikelyHasPrimitiveParameters()); assertFalse(function.getHasPythonSideEffects()); + assertFalse(function.getIsHybrid()); } @Test @@ -4874,6 +4876,7 @@ public void testModel10() throws Exception { assertTrue(function.getLikelyHasTensorParameter()); assertFalse(function.getLikelyHasPrimitiveParameters()); assertFalse(function.getHasPythonSideEffects()); + assertFalse(function.getIsHybrid()); } @Test @@ -4882,6 +4885,7 @@ public void testModel11() throws Exception { assertTrue(function.getLikelyHasTensorParameter()); assertFalse(function.getLikelyHasPrimitiveParameters()); assertFalse(function.getHasPythonSideEffects()); + assertFalse(function.getIsHybrid()); } @Test @@ -4890,6 +4894,7 @@ public void testModel12() throws Exception { assertTrue(function.getLikelyHasTensorParameter()); assertFalse(function.getLikelyHasPrimitiveParameters()); assertFalse(function.getHasPythonSideEffects()); + assertFalse(function.getIsHybrid()); } @Test @@ -4898,6 +4903,61 @@ public void testModel13() throws Exception { assertTrue(function.getLikelyHasTensorParameter()); assertFalse(function.getLikelyHasPrimitiveParameters()); assertFalse(function.getHasPythonSideEffects()); + assertFalse(function.getIsHybrid()); + } + + @Test + public void testModel14() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + assertTrue(function.getIsHybrid()); + } + + @Test + public void testModel15() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + assertTrue(function.getIsHybrid()); + } + + @Test + public void testModel16() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + assertTrue(function.getIsHybrid()); + } + + @Test + public void testModel17() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + assertTrue(function.getIsHybrid()); + } + + @Test + public void testModel18() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + assertTrue(function.getIsHybrid()); + } + + @Test + public void testModel19() throws Exception { + Function function = this.getSingleFunction(); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + assertFalse(function.getHasPythonSideEffects()); + assertTrue(function.getIsHybrid()); } // TODO: Test models that have tf.functions. From 9917590f636ce1505307b44bb6c92791a2504a42 Mon Sep 17 00:00:00 2001 From: Raffi Khatchadourian Date: Tue, 5 Mar 2024 12:42:24 -0500 Subject: [PATCH 4/8] Always follow type hints. --- .../hybridize/core/analysis/Function.java | 72 ++++++++++++------- .../hybridize/core/analysis/Information.java | 28 ++++++++ ...HybridizeFunctionRefactoringProcessor.java | 48 ++++++++++++- .../hunter/hybridize/core/utils/Util.java | 4 +- .../Evaluate Hybridize Functions.launch | 2 +- ...teHybridizeFunctionRefactoringHandler.java | 10 ++- .../testHasLikelyTensorParameter158/in/A.py | 13 ++++ .../in/requirements.txt | 1 + .../HybridizeFunctionRefactoringTest.java | 22 +++++- 9 files changed, 167 insertions(+), 33 deletions(-) create mode 100644 edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Information.java create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testHasLikelyTensorParameter158/in/A.py create mode 100644 edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testHasLikelyTensorParameter158/in/requirements.txt diff --git a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java index da8b401b..1be91904 100644 --- a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java +++ b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java @@ -1,5 +1,6 @@ package edu.cuny.hunter.hybridize.core.analysis; +import static edu.cuny.hunter.hybridize.core.analysis.Information.TYPE_INFERENCING; import static edu.cuny.hunter.hybridize.core.analysis.PreconditionFailure.HAS_PRIMITIVE_PARAMETERS; import static edu.cuny.hunter.hybridize.core.analysis.PreconditionFailure.HAS_PYTHON_SIDE_EFFECTS; import static edu.cuny.hunter.hybridize.core.analysis.PreconditionSuccess.P1; @@ -386,11 +387,14 @@ public boolean getReduceRetracingParamExists() { private boolean ignoreBooleans; + private boolean alwaysFollowTypeHints; + private static Map>> creationsCache = Maps.newHashMap(); - public Function(FunctionDefinition fd, boolean ignoreBooleans) { + public Function(FunctionDefinition fd, boolean ignoreBooleans, boolean alwaysFollowTypeHints) { this.functionDefinition = fd; this.ignoreBooleans = ignoreBooleans; + this.alwaysFollowTypeHints = alwaysFollowTypeHints; } public void computeRecursion(CallGraph callGraph) throws CantComputeRecursionException { @@ -784,29 +788,30 @@ public void inferTensorTensorParameters(TensorTypeAnalysis analysis, CallGraph c continue; // next parameter. // check a special case where we consider type hints. - - // if hybridization parameters are specified. - if (this.getHybridizationParameters() != null) { - // if we are considering type hints. - // TODO: Actually get the value here (#111). - if (this.getHybridizationParameters().getExperimentalFollowTypeHintsParamExists()) { - LOG.info("Following type hints for: " + this + " and parameter: " + paramName + "."); - - // try to get its type from the AST. - TypeInfo argTypeInfo = NodeUtils.getTypeForParameterFromAST(paramName, functionDef); - - if (argTypeInfo != null) { - LOG.info("Found type for parameter " + paramName + " in " + this + ": " + argTypeInfo.getActTok() + "."); - - exprType node = argTypeInfo.getNode(); - Set allAttributes = getAllAttributes(node); - - if (attributesHaveTensorTypeHints(allAttributes, monitor.slice(IProgressMonitor.UNKNOWN))) { - this.likelyHasTensorParameter = Boolean.TRUE; - LOG.info(this + " likely has a tensor parameter: " + paramName + " due to a type hint."); - monitor.worked(1); - continue; // next parameter. - } + boolean followTypeHints = this.getAlwaysFollowTypeHints() || this.getHybridizationParameters() != null + && this.getHybridizationParameters().getExperimentalFollowTypeHintsParamExists(); // TODO: Actually get the + // value here (#111). + + // if we are considering type hints. + if (followTypeHints) { + LOG.info("Following type hints for: " + this + " and parameter: " + paramName + "."); + + // try to get its type from the AST. + TypeInfo argTypeInfo = NodeUtils.getTypeForParameterFromAST(paramName, functionDef); + + if (argTypeInfo != null) { + LOG.info("Found type for parameter " + paramName + " in " + this + ": " + argTypeInfo.getActTok() + "."); + + exprType node = argTypeInfo.getNode(); + Set allAttributes = getAllAttributes(node); + + if (attributesHaveTensorTypeHints(allAttributes, monitor.slice(IProgressMonitor.UNKNOWN))) { + this.likelyHasTensorParameter = Boolean.TRUE; + LOG.info(this + " likely has a tensor parameter: " + paramName + " due to a type hint."); + monitor.worked(1); + this.addInfo(TYPE_INFERENCING, "Used a type hint to infer tensor type for parameter: " + paramName + + " in function: " + this + "."); + continue; // next parameter. } } } @@ -1203,7 +1208,15 @@ public void addWarning(String message) { } public void addInfo(String message) { - addStatus(RefactoringStatus.INFO, message, RefactoringStatusEntry.NO_CODE); + this.addInfo(message, RefactoringStatusEntry.NO_CODE); + } + + public void addInfo(Information information, String message) { + this.addInfo(message, information.getCode()); + } + + private void addInfo(String message, int code) { + addStatus(RefactoringStatus.INFO, message, code); } private void addStatus(int status, String message, int code) { @@ -1568,4 +1581,13 @@ public boolean isMethod() { protected boolean getIgnoreBooleans() { return ignoreBooleans; } + + /** + * Returns true iff we should use type hints regardless of a hybridization parameter. + * + * @return Whether we should use type hints regardless of what is specified in any hybridization parameters. + */ + public boolean getAlwaysFollowTypeHints() { + return alwaysFollowTypeHints; + } } diff --git a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Information.java b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Information.java new file mode 100644 index 00000000..78f9e3e5 --- /dev/null +++ b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Information.java @@ -0,0 +1,28 @@ +package edu.cuny.hunter.hybridize.core.analysis; + +import java.util.Arrays; + +public enum Information { + + /** + * Information related to (tensor) type inferencing. + */ + TYPE_INFERENCING(1); + + static { + // check that the codes are unique. + assert Arrays.stream(Information.values()).map(Information::getCode).distinct() + .count() == Information.values().length : "Codes must be unique."; + } + + private int code; + + private Information(int code) { + this.code = code; + } + + public int getCode() { + return this.code; + } + +} diff --git a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/refactorings/HybridizeFunctionRefactoringProcessor.java b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/refactorings/HybridizeFunctionRefactoringProcessor.java index b3372a70..92774d08 100644 --- a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/refactorings/HybridizeFunctionRefactoringProcessor.java +++ b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/refactorings/HybridizeFunctionRefactoringProcessor.java @@ -119,6 +119,11 @@ private static RefactoringStatus checkParameters(Function func) { */ private boolean useTestEntryPoints; + /** + * True iff we should use type hints regardless of any hybridization arguments. + */ + private boolean alwaysFollowTypeHints; + public HybridizeFunctionRefactoringProcessor() { // Force the use of typeshed. It's an experimental feature of PyDev. InterpreterGeneralPreferences.FORCE_USE_TYPESHED = TRUE; @@ -155,6 +160,13 @@ public HybridizeFunctionRefactoringProcessor(boolean alwaysCheckPythonSideEffect this.useTestEntryPoints = useTestEntryPoints; } + public HybridizeFunctionRefactoringProcessor(boolean alwaysCheckPythonSideEffects, boolean processFunctionsInParallel, + boolean alwaysCheckRecusion, boolean ignoreBooleansInLiteralCheck, boolean useTestEntryPoints, boolean alwaysFollowTypeHints) { + this(alwaysCheckPythonSideEffects, processFunctionsInParallel, alwaysCheckRecusion, ignoreBooleansInLiteralCheck, + useTestEntryPoints); + this.alwaysFollowTypeHints = alwaysFollowTypeHints; + } + public HybridizeFunctionRefactoringProcessor(Set functionDefinitionSet) throws TooManyMatchesException /* FIXME: This exception sounds too low-level. */ { this(); @@ -164,7 +176,7 @@ public HybridizeFunctionRefactoringProcessor(Set functionDef Set functionSet = this.getFunctions(); for (FunctionDefinition fd : functionDefinitionSet) { - Function function = new Function(fd, this.ignoreBooleansInLiteralCheck); + Function function = new Function(fd, this.ignoreBooleansInLiteralCheck, this.alwaysFollowTypeHints); // Add the Function to the Function set. functionSet.add(function); @@ -198,6 +210,31 @@ public HybridizeFunctionRefactoringProcessor(Set functionDef this.useTestEntryPoints = useTestEntryPoints; } + public HybridizeFunctionRefactoringProcessor(Set functionDefinitionSet, boolean alwaysCheckPythonSideEffects, + boolean processFunctionsInParallel, boolean alwaysCheckRecursion, boolean useTestEntryPoints, boolean alwaysFollowTypeHints) + throws TooManyMatchesException /* FIXME: This exception sounds too low-level. */ { + this(); + + this.alwaysCheckPythonSideEffects = alwaysCheckPythonSideEffects; + this.alwaysCheckRecursion = alwaysCheckRecursion; + this.processFunctionsInParallel = processFunctionsInParallel; + this.useTestEntryPoints = useTestEntryPoints; + this.alwaysFollowTypeHints = alwaysFollowTypeHints; + + // Convert the FunctionDefs to Functions. + if (functions != null) { + Set functionSet = this.getFunctions(); + + for (FunctionDefinition fd : functionDefinitionSet) { + Function function = new Function(fd, this.ignoreBooleansInLiteralCheck, this.alwaysFollowTypeHints); + + // Add the Function to the Function set. + functionSet.add(function); + } + } + + } + @Override public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException, OperationCanceledException { @@ -511,4 +548,13 @@ private boolean getProcessFunctionsInParallel() { protected boolean shouldUseTestEntryPoints() { return useTestEntryPoints; } + + /** + * Returns true iff we should follow type hints regardless of any hybridization arguments. + * + * @return True iff we should follow type hints regardless of any hybridization arguments. + */ + public boolean getAlwaysFollowTypeHints() { + return alwaysFollowTypeHints; + } } diff --git a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/utils/Util.java b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/utils/Util.java index 57be73ca..e63ee0ea 100644 --- a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/utils/Util.java +++ b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/utils/Util.java @@ -50,10 +50,10 @@ public static Refactoring createRefactoring(Set functionDefi public static HybridizeFunctionRefactoringProcessor createHybridizeFunctionRefactoring(IProject[] projects, boolean alwaysCheckPythonSideEffects, boolean processFunctionsInParallel, boolean alwaysCheckRecusion, - boolean useTestEntryPoints) throws ExecutionException, CoreException, IOException { + boolean useTestEntryPoints, boolean alwaysFollowTypeHints) throws ExecutionException, CoreException, IOException { Set functionDefinitions = getFunctionDefinitions(Arrays.asList(projects)); return new HybridizeFunctionRefactoringProcessor(functionDefinitions, alwaysCheckPythonSideEffects, processFunctionsInParallel, - alwaysCheckRecusion, useTestEntryPoints); + alwaysCheckRecusion, useTestEntryPoints, alwaysFollowTypeHints); } public static Set getFunctionDefinitions(Iterable iterable) diff --git a/edu.cuny.hunter.hybridize.eval/Evaluate Hybridize Functions.launch b/edu.cuny.hunter.hybridize.eval/Evaluate Hybridize Functions.launch index e471771d..93e75042 100644 --- a/edu.cuny.hunter.hybridize.eval/Evaluate Hybridize Functions.launch +++ b/edu.cuny.hunter.hybridize.eval/Evaluate Hybridize Functions.launch @@ -23,7 +23,7 @@ - + diff --git a/edu.cuny.hunter.hybridize.eval/src/edu/cuny/hunter/hybridize/eval/handlers/EvaluateHybridizeFunctionRefactoringHandler.java b/edu.cuny.hunter.hybridize.eval/src/edu/cuny/hunter/hybridize/eval/handlers/EvaluateHybridizeFunctionRefactoringHandler.java index 2d10f72f..c737a092 100644 --- a/edu.cuny.hunter.hybridize.eval/src/edu/cuny/hunter/hybridize/eval/handlers/EvaluateHybridizeFunctionRefactoringHandler.java +++ b/edu.cuny.hunter.hybridize.eval/src/edu/cuny/hunter/hybridize/eval/handlers/EvaluateHybridizeFunctionRefactoringHandler.java @@ -80,6 +80,8 @@ public class EvaluateHybridizeFunctionRefactoringHandler extends EvaluateRefacto private static final String USE_TEST_ENTRYPOINTS_KEY = "edu.cuny.hunter.hybridize.eval.useTestEntrypoints"; + private static final String ALWAYS_FOLLOW_TYPE_HINTS_KEY = "edu.cuny.hunter.hybridize.eval.alwaysFollowTypeHints"; + private static String[] buildAttributeColumnNames(String... additionalColumnNames) { String[] primaryColumns = new String[] { "subject", "function", "module", "relative path" }; List ret = new ArrayList<>(Arrays.asList(primaryColumns)); @@ -105,6 +107,8 @@ private static Object[] buildAttributeColumnValues(Function function, Object... private boolean useTestEntrypoints = Boolean.getBoolean(USE_TEST_ENTRYPOINTS_KEY); + private boolean alwaysFollowTypeHints = Boolean.getBoolean(ALWAYS_FOLLOW_TYPE_HINTS_KEY); + @Override public Object execute(ExecutionEvent event) throws ExecutionException { Job.create("Evaluating Hybridize Functions refactoring...", monitor -> { @@ -148,7 +152,7 @@ public Object execute(ExecutionEvent event) throws ExecutionException { resultsTimeCollector.start(); processor = createHybridizeFunctionRefactoring(new IProject[] { project }, this.getAlwaysCheckPythonSideEffects(), - this.getProcessFunctionsInParallel(), this.getAlwaysCheckRecusion(), this.getUseTestEntrypoints()); + this.getProcessFunctionsInParallel(), this.getAlwaysCheckRecusion(), this.getUseTestEntrypoints(), this.getAlwaysFollowTypeHints()); resultsTimeCollector.stop(); // run the precondition checking. @@ -383,4 +387,8 @@ private boolean getProcessFunctionsInParallel() { private boolean getUseTestEntrypoints() { return this.useTestEntrypoints; } + + public boolean getAlwaysFollowTypeHints() { + return alwaysFollowTypeHints; + } } diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testHasLikelyTensorParameter158/in/A.py b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testHasLikelyTensorParameter158/in/A.py new file mode 100644 index 00000000..5e2d7123 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testHasLikelyTensorParameter158/in/A.py @@ -0,0 +1,13 @@ +# From https://www.tensorflow.org/guide/function#usage. + +import tensorflow as tf + + +@tf.function +def add(t: tuple[tf.Tensor, tf.Tensor]): + return t[0] + t[1] + + +arg = (tf.constant(2), tf.constant(2)) +assert type(arg) == tuple +result = add(arg) diff --git a/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testHasLikelyTensorParameter158/in/requirements.txt b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testHasLikelyTensorParameter158/in/requirements.txt new file mode 100644 index 00000000..b154f958 --- /dev/null +++ b/edu.cuny.hunter.hybridize.tests/resources/HybridizeFunction/testHasLikelyTensorParameter158/in/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.9.3 diff --git a/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java b/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java index 6da33f52..081b4bcb 100644 --- a/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java +++ b/edu.cuny.hunter.hybridize.tests/test cases/edu/cuny/hunter/hybridize/tests/HybridizeFunctionRefactoringTest.java @@ -164,6 +164,8 @@ public int getInterpreterType() throws CoreException { private static final boolean USE_TEST_ENTRYPOINTS = true; + private static final boolean ALWAYS_FOLLOW_TYPE_HINTS = true; + /** * Whether we should run the function processing in parallel. Running in parallel makes the logs difficult to read and doesn't offer * much in way of speedup since each test has only a few {@link Function}s. @@ -586,7 +588,8 @@ private Set getFunctions(String fileNameWithoutExtension) throws Excep .map(f -> new FunctionDefinition(f, fileNameWithoutExtension, inputTestFile, document, nature)).collect(Collectors.toSet()); HybridizeFunctionRefactoringProcessor processor = new HybridizeFunctionRefactoringProcessor(inputFunctionDefinitions, - ALWAYS_CHECK_PYTHON_SIDE_EFFECTS, PROCESS_FUNCTIONS_IN_PARALLEL, ALWAYS_CHECK_RECURSION, USE_TEST_ENTRYPOINTS); + ALWAYS_CHECK_PYTHON_SIDE_EFFECTS, PROCESS_FUNCTIONS_IN_PARALLEL, ALWAYS_CHECK_RECURSION, USE_TEST_ENTRYPOINTS, + ALWAYS_FOLLOW_TYPE_HINTS); ProcessorBasedRefactoring refactoring = new ProcessorBasedRefactoring(processor); @@ -1785,7 +1788,8 @@ public void testHasLikelyTensorParameter7() throws Exception { /** * Test for #2. Here, the function has one parameters, is hybrid, and does not consider type hints. But, a type hint is supplied. In - * other words, a type hint supplied but we don't use it. Thus, it's not likely to have a tensor parameter. + * other words, a type hint supplied. We use it because of our option but not because of any hybridization parameters. Thus, it's likely + * to have a tensor parameter. */ @Test public void testHasLikelyTensorParameter8() throws Exception { @@ -1824,7 +1828,7 @@ public void testHasLikelyTensorParameter8() throws Exception { String attributeName = NodeUtils.getFullRepresentationString(typeHint); assertEquals("tf.Tensor", attributeName); - assertFalse(function.getLikelyHasTensorParameter()); + assertTrue(function.getLikelyHasTensorParameter()); } /** @@ -4588,6 +4592,18 @@ public void testHasLikelyTensorParameter157() throws Exception { testHasLikelyTensorParameterHelper(false, true); } + /** + * Use the type hint here even though experimental_follow_type_hints isn't supplied. + */ + @Test + public void testHasLikelyTensorParameter158() throws Exception { + Function function = getFunction("add"); + assertTrue(function.getIsHybrid()); + assertTrue(function.getLikelyHasTensorParameter()); + assertFalse(function.getLikelyHasPrimitiveParameters()); + + } + // TODO: Test arbitrary expression. // TODO: Test cast/assert statements? // TODO: https://www.tensorflow.org/guide/function#pass_tensors_instead_of_python_literals. How do we deal with union types? Do we want From dc72c3a8fe523958ec51725b66d6dc4e669926b2 Mon Sep 17 00:00:00 2001 From: Raffi Khatchadourian Date: Tue, 5 Mar 2024 12:43:29 -0500 Subject: [PATCH 5/8] Add Javadoc. --- .../src/edu/cuny/hunter/hybridize/core/analysis/Function.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java index 1be91904..05bb8939 100644 --- a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java +++ b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java @@ -769,6 +769,9 @@ public TypeReference getDeclaringClass() { return TypeReference.findOrCreate(PythonTypes.pythonLoader, typeName); } + /** + * Infer which parameters are likely tensor parameters. + */ public void inferTensorTensorParameters(TensorTypeAnalysis analysis, CallGraph callGraph, IProgressMonitor monitor) throws Exception { monitor.beginTask("Analyzing whether function has a tensor parameter.", IProgressMonitor.UNKNOWN); // TODO: Use cast/assert statements? From 431df52e4ff189f964b1a7f222cd6af0e72fee18 Mon Sep 17 00:00:00 2001 From: Raffi Khatchadourian Date: Tue, 5 Mar 2024 12:43:35 -0500 Subject: [PATCH 6/8] Whitespace. --- .../src/edu/cuny/hunter/hybridize/core/analysis/Function.java | 1 + 1 file changed, 1 insertion(+) diff --git a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java index 05bb8939..fe11d3b9 100644 --- a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java +++ b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java @@ -774,6 +774,7 @@ public TypeReference getDeclaringClass() { */ public void inferTensorTensorParameters(TensorTypeAnalysis analysis, CallGraph callGraph, IProgressMonitor monitor) throws Exception { monitor.beginTask("Analyzing whether function has a tensor parameter.", IProgressMonitor.UNKNOWN); + // TODO: Use cast/assert statements? FunctionDef functionDef = this.getFunctionDefinition().getFunctionDef(); argumentsType params = functionDef.args; From 02e23d01d706614d0f8c6e1407d8e2b2ae20750f Mon Sep 17 00:00:00 2001 From: Raffi Khatchadourian Date: Tue, 5 Mar 2024 12:49:51 -0500 Subject: [PATCH 7/8] Whitespace. --- .../refactorings/HybridizeFunctionRefactoringProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/refactorings/HybridizeFunctionRefactoringProcessor.java b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/refactorings/HybridizeFunctionRefactoringProcessor.java index 92774d08..97a1f0fe 100644 --- a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/refactorings/HybridizeFunctionRefactoringProcessor.java +++ b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/refactorings/HybridizeFunctionRefactoringProcessor.java @@ -551,7 +551,7 @@ protected boolean shouldUseTestEntryPoints() { /** * Returns true iff we should follow type hints regardless of any hybridization arguments. - * + * * @return True iff we should follow type hints regardless of any hybridization arguments. */ public boolean getAlwaysFollowTypeHints() { From e4a684a6fa331f222f31c7c534933442ab5a323b Mon Sep 17 00:00:00 2001 From: Raffi Khatchadourian Date: Tue, 5 Mar 2024 13:22:06 -0500 Subject: [PATCH 8/8] Format. --- .../src/edu/cuny/hunter/hybridize/core/analysis/Function.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java index fe11d3b9..0059e153 100644 --- a/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java +++ b/edu.cuny.hunter.hybridize.core/src/edu/cuny/hunter/hybridize/core/analysis/Function.java @@ -793,8 +793,8 @@ public void inferTensorTensorParameters(TensorTypeAnalysis analysis, CallGraph c // check a special case where we consider type hints. boolean followTypeHints = this.getAlwaysFollowTypeHints() || this.getHybridizationParameters() != null - && this.getHybridizationParameters().getExperimentalFollowTypeHintsParamExists(); // TODO: Actually get the - // value here (#111). + // TODO: Actually get the value here (#111). + && this.getHybridizationParameters().getExperimentalFollowTypeHintsParamExists(); // if we are considering type hints. if (followTypeHints) {