diff --git a/CHANGELOG.md b/CHANGELOG.md
index f97f08d..be6acee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
+- Add rule GCI99 Optimize square computation (scalar vs vectorized method)
+
### Changed
- compatibility updates for SonarQube 25.5.0
diff --git a/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java b/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java
index c385979..60189c4 100644
--- a/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java
+++ b/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java
@@ -40,7 +40,8 @@ public class PythonRuleRepository implements RulesDefinition, PythonCustomRuleRe
AvoidFullSQLRequest.class,
AvoidListComprehensionInIterations.class,
DetectUnoptimizedImageFormat.class,
- AvoidMultipleIfElseStatementCheck.class
+ AvoidMultipleIfElseStatementCheck.class,
+ OptimizeSquareComputation.class
);
public static final String LANGUAGE = "py";
diff --git a/src/main/java/org/greencodeinitiative/creedengo/python/checks/OptimizeSquareComputation.java b/src/main/java/org/greencodeinitiative/creedengo/python/checks/OptimizeSquareComputation.java
new file mode 100644
index 0000000..a2dc239
--- /dev/null
+++ b/src/main/java/org/greencodeinitiative/creedengo/python/checks/OptimizeSquareComputation.java
@@ -0,0 +1,91 @@
+/*
+ * creedengo - Python language - Provides rules to reduce the environmental footprint of your Python programs
+ * Copyright © 2024 Green Code Initiative (https://green-code-initiative.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.greencodeinitiative.creedengo.python.checks;
+
+import org.sonar.check.Rule;
+import org.sonar.plugins.python.api.PythonSubscriptionCheck;
+import org.sonar.plugins.python.api.SubscriptionContext;
+import org.sonar.plugins.python.api.tree.BinaryExpression;
+import org.sonar.plugins.python.api.tree.CallExpression;
+import org.sonar.plugins.python.api.tree.Expression;
+import org.sonar.plugins.python.api.tree.NumericLiteral;
+import org.sonar.plugins.python.api.tree.QualifiedExpression;
+import org.sonar.plugins.python.api.tree.RegularArgument;
+
+import static org.sonar.plugins.python.api.tree.Tree.Kind.*;
+
+@Rule(key = "GCI99")
+public class OptimizeSquareComputation extends PythonSubscriptionCheck {
+
+ public static final String DESCRIPTION = "Use x*x instead of x**2 or math.pow(x,2) to calculate the square of a value";
+
+ @Override
+ public void initialize(Context context) {
+ context.registerSyntaxNodeConsumer(CALL_EXPR, this::checkMathPowCall);
+ context.registerSyntaxNodeConsumer(POWER, this::checkPowerOf2);
+ }
+
+
+ private boolean isNumericLiteralWithValue(Expression expr, String value) {
+ if (expr.is(NUMERIC_LITERAL)) {
+ NumericLiteral numericLiteral = (NumericLiteral) expr;
+ return value.equals(numericLiteral.valueAsString());
+ }
+ return false;
+ }
+
+ private void checkMathPowCall(SubscriptionContext context) {
+ CallExpression callExpression = (CallExpression) context.syntaxNode();
+
+
+ if (isMathPowCall(callExpression)) {
+ context.addIssue(callExpression, DESCRIPTION);
+ }
+ }
+
+ private boolean isMathPowCall(CallExpression callExpression) {
+ Expression callee = callExpression.callee();
+
+
+ if (callee.is(QUALIFIED_EXPR)) {
+ QualifiedExpression qualifiedExpr = (QualifiedExpression) callee;
+ String name = qualifiedExpr.name().name();
+
+
+ if ("pow".equals(name)) {
+
+ if (callExpression.arguments().size() >= 2) {
+ Expression secondArg = ((RegularArgument)callExpression.arguments().get(1)).expression();
+ return isNumericLiteralWithValue(secondArg, "2");
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private void checkPowerOf2(SubscriptionContext context) {
+ BinaryExpression power = (BinaryExpression) context.syntaxNode();
+
+
+ if (isNumericLiteralWithValue(power.rightOperand(), "2")) {
+ context.addIssue(power, DESCRIPTION);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/greencodeinitiative/creedengo/python/checks/OptimizeSquareComputationTest.java b/src/test/java/org/greencodeinitiative/creedengo/python/checks/OptimizeSquareComputationTest.java
new file mode 100644
index 0000000..8bcc6de
--- /dev/null
+++ b/src/test/java/org/greencodeinitiative/creedengo/python/checks/OptimizeSquareComputationTest.java
@@ -0,0 +1,29 @@
+/*
+ * creedengo - Python language - Provides rules to reduce the environmental footprint of your Python programs
+ * Copyright © 2024 Green Code Initiative (https://green-code-initiative.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.greencodeinitiative.creedengo.python.checks;
+
+import org.junit.Test;
+import org.sonar.python.checks.utils.PythonCheckVerifier;
+
+public class OptimizeSquareComputationTest {
+
+ @Test
+ public void test() {
+ PythonCheckVerifier.verify("src/test/resources/checks/optimizeSquareComputation.py", new OptimizeSquareComputation());
+ }
+}
diff --git a/src/test/resources/checks/optimizeSquareComputation.py b/src/test/resources/checks/optimizeSquareComputation.py
new file mode 100644
index 0000000..dd8fbea
--- /dev/null
+++ b/src/test/resources/checks/optimizeSquareComputation.py
@@ -0,0 +1,42 @@
+import math
+
+x = 5
+result1 = x**2 # Noncompliant {{Use x*x instead of x**2 or math.pow(x,2) to calculate the square of a value}}
+
+z = 7
+result4 = math.pow(z, 2) # Noncompliant {{Use x*x instead of x**2 or math.pow(x,2) to calculate the square of a value}}
+
+a = 3
+result5 = a*a
+
+b = 4
+result6 = b*3
+result7 = 5*b
+result8 = math.pow(b, 3)
+result9 = b**3
+
+c = 2.5
+result10 = c**2 # Noncompliant {{Use x*x instead of x**2 or math.pow(x,2) to calculate the square of a value}}
+result11 = math.pow(c, 2) # Noncompliant {{Use x*x instead of x**2 or math.pow(x,2) to calculate the square of a value}}
+
+
+d = 8
+e = 9
+result12 = math.pow(d+e, 2) # Noncompliant {{Use x*x instead of x**2 or math.pow(x,2) to calculate the square of a value}}
+result13 = (d+e)**2 # Noncompliant {{Use x*x instead of x**2 or math.pow(x,2) to calculate the square of a value}}
+result14 = (d+e)*(d+e)
+
+
+def square(x):
+ return x**2 # Noncompliant {{Use x*x instead of x**2 or math.pow(x,2) to calculate the square of a value}}
+
+def better_square(x):
+ return x*x
+
+
+import math as m
+result15 = m.pow(d, 2) # Noncompliant {{Use x*x instead of x**2 or math.pow(x,2) to calculate the square of a value}}
+
+result16 = math.sqrt(d)
+result17 = math.sin(d)
+result18 = math.pow(d, 1.5)
\ No newline at end of file