Explorar el Código

Add remaining trigonometric functions (ESQL-1518)

Adds the remaining trigonomentric functions, `ACOS`, `ASIN`, `ATAN`, and
`ATAN2`.

---------

Co-authored-by: Bogdan Pintea <pintea@mailbox.org>
Nik Everett hace 2 años
padre
commit
c1601f5a9c
Se han modificado 22 ficheros con 915 adiciones y 0 borrados
  1. 8 0
      docs/reference/esql/esql-functions.asciidoc
  2. 12 0
      docs/reference/esql/functions/acos.asciidoc
  3. 12 0
      docs/reference/esql/functions/asin.asciidoc
  4. 12 0
      docs/reference/esql/functions/atan.asciidoc
  5. 14 0
      docs/reference/esql/functions/atan2.asciidoc
  6. 70 0
      x-pack/plugin/esql/qa/testFixtures/src/main/resources/floats.csv-spec
  7. 29 0
      x-pack/plugin/esql/qa/testFixtures/src/main/resources/ints.csv-spec
  8. 4 0
      x-pack/plugin/esql/qa/testFixtures/src/main/resources/show.csv-spec
  9. 64 0
      x-pack/plugin/esql/src/main/java/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosEvaluator.java
  10. 64 0
      x-pack/plugin/esql/src/main/java/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinEvaluator.java
  11. 80 0
      x-pack/plugin/esql/src/main/java/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Evaluator.java
  12. 64 0
      x-pack/plugin/esql/src/main/java/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanEvaluator.java
  13. 8 0
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java
  14. 45 0
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Acos.java
  15. 45 0
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Asin.java
  16. 45 0
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan.java
  17. 106 0
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2.java
  18. 20 0
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java
  19. 53 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosTests.java
  20. 53 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinTests.java
  21. 54 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Tests.java
  22. 53 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanTests.java

+ 8 - 0
docs/reference/esql/esql-functions.asciidoc

@@ -9,6 +9,10 @@
 these functions:
 
 * <<esql-abs>>
+* <<esql-acos>>
+* <<esql-asin>>
+* <<esql-atan>>
+* <<esql-atan2>>
 * <<esql-auto_bucket>>
 * <<esql-case>>
 * <<esql-cidr_match>>
@@ -59,6 +63,10 @@ these functions:
 * <<esql-trim>>
 
 include::functions/abs.asciidoc[]
+include::functions/acos.asciidoc[]
+include::functions/asin.asciidoc[]
+include::functions/atan.asciidoc[]
+include::functions/atan2.asciidoc[]
 include::functions/auto_bucket.asciidoc[]
 include::functions/case.asciidoc[]
 include::functions/cidr_match.asciidoc[]

+ 12 - 0
docs/reference/esql/functions/acos.asciidoc

@@ -0,0 +1,12 @@
+[[esql-acos]]
+=== `ACOS`
+Inverse https://en.wikipedia.org/wiki/Inverse_trigonometric_functions[cosine] trigonometric function.
+
+[source.merge.styled,esql]
+----
+include::{esql-specs}/floats.csv-spec[tag=acos]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/floats.csv-spec[tag=acos-result]
+|===

+ 12 - 0
docs/reference/esql/functions/asin.asciidoc

@@ -0,0 +1,12 @@
+[[esql-asin]]
+=== `ASIN`
+Inverse https://en.wikipedia.org/wiki/Inverse_trigonometric_functions[sine] trigonometric function.
+
+[source.merge.styled,esql]
+----
+include::{esql-specs}/floats.csv-spec[tag=asin]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/floats.csv-spec[tag=asin-result]
+|===

+ 12 - 0
docs/reference/esql/functions/atan.asciidoc

@@ -0,0 +1,12 @@
+[[esql-atan]]
+=== `ATAN`
+Inverse https://en.wikipedia.org/wiki/Inverse_trigonometric_functions[tangent] trigonometric function.
+
+[source.merge.styled,esql]
+----
+include::{esql-specs}/floats.csv-spec[tag=atan]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/floats.csv-spec[tag=atan-result]
+|===

+ 14 - 0
docs/reference/esql/functions/atan2.asciidoc

@@ -0,0 +1,14 @@
+[[esql-atan2]]
+=== `ATAN2`
+
+The https://en.wikipedia.org/wiki/Atan2[angle] between the positive x-axis and the
+ray from the origin to the point (x , y) in the Cartesian plane.
+
+[source.merge.styled,esql]
+----
+include::{esql-specs}/floats.csv-spec[tag=atan2]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/floats.csv-spec[tag=atan2-result]
+|===

+ 70 - 0
x-pack/plugin/esql/qa/testFixtures/src/main/resources/floats.csv-spec

@@ -257,6 +257,28 @@ a:double | cosh:double
 // end::cosh-result[]
 ;
 
+acos
+// tag::acos[]
+ROW a=.9
+| EVAL acos=ACOS(a)
+// end::acos[]
+;
+
+// tag::acos-result[]
+a:double | acos:double
+      .9 | 0.45102681179626236
+// end::acos-result[]
+;
+
+acosNan
+ROW a=12.0
+| EVAL acos=ACOS(a)
+;
+
+a:double | acos:double
+      12 | NaN
+;
+
 sin
 // tag::sin[]
 ROW a=1.8 
@@ -283,6 +305,28 @@ a:double | sinh:double
 // end::sinh-result[]
 ;
 
+asin
+// tag::asin[]
+ROW a=.9
+| EVAL asin=ASIN(a)
+// end::asin[]
+;
+
+// tag::asin-result[]
+a:double | asin:double
+      .9 | 1.1197695149986342
+// end::asin-result[]
+;
+
+asinNan
+ROW a=12.0
+| EVAL asin=ASIN(a)
+;
+
+a:double | asin:double
+      12 | NaN
+;
+
 tan
 // tag::tan[]
 ROW a=1.8 
@@ -308,3 +352,29 @@ a:double | tanh:double
      1.8 | 0.9468060128462683
 // end::tanh-result[]
 ;
+
+atan
+// tag::atan[]
+ROW a=12.9
+| EVAL atan=ATAN(a)
+// end::atan[]
+;
+
+// tag::atan-result[]
+a:double | atan:double
+    12.9 | 1.4934316673669235
+// end::atan-result[]
+;
+
+atan2
+// tag::atan2[]
+ROW y=12.9, x=.6
+| EVAL atan2=ATAN2(y, x)
+// end::atan2[]
+;
+
+// tag::atan2-result[]
+y:double | x:double | atan2:double
+    12.9 |      0.6 | 1.5243181954438936
+// end::atan2-result[]
+;

+ 29 - 0
x-pack/plugin/esql/qa/testFixtures/src/main/resources/ints.csv-spec

@@ -388,6 +388,13 @@ a:integer | cos:double
         2 | -0.4161468365471424
 ;
 
+acos
+ROW a=1 | EVAL acos=ACOS(a);
+
+a:integer | acos:double
+        1 | 0.0
+;
+
 cosh
 ROW a=2 | EVAL cosh=COSH(a);
 
@@ -409,6 +416,14 @@ a:integer | sinh:double
         2 | 3.626860407847019
 ;
 
+asin
+ROW a=1 | EVAL asin=ASIN(a);
+
+a:integer | asin:double
+        1 | 1.5707963267948966
+;
+
+
 tan
 ROW a=2 | EVAL tan=TAN(a);
 
@@ -422,3 +437,17 @@ ROW a=2 | EVAL tanh=TANH(a);
 a:integer | tanh:double
         2 | 0.9640275800758169
 ;
+
+atan
+ROW a=2 | EVAL atan=ATAN(a);
+
+a:integer | atan:double
+        2 | 1.1071487177940904
+;
+
+atan2
+ROW y=2, x=12 | EVAL atan2=ATAN2(y, x);
+
+y:integer | x:integer | atan2:double
+        2 |        12 | 0.16514867741462683
+;

+ 4 - 0
x-pack/plugin/esql/qa/testFixtures/src/main/resources/show.csv-spec

@@ -10,6 +10,10 @@ show functions;
 
   name:keyword           |           synopsis:keyword
 abs                      |abs(arg1)
+acos                     |acos(arg1)
+asin                     |asin(arg1)
+atan                     |atan(arg1)
+atan2                    |atan2(arg1, arg2)
 auto_bucket              |auto_bucket(arg1, arg2, arg3, arg4)
 avg                      |avg(arg1)
 case                     |case(arg1...)

+ 64 - 0
x-pack/plugin/esql/src/main/java/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosEvaluator.java

@@ -0,0 +1,64 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License
+// 2.0; you may not use this file except in compliance with the Elastic License
+// 2.0.
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.DoubleVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.EvalOperator;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Acos}.
+ * This class is generated. Do not edit it.
+ */
+public final class AcosEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final EvalOperator.ExpressionEvaluator val;
+
+  public AcosEvaluator(EvalOperator.ExpressionEvaluator val) {
+    this.val = val;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    Block valUncastBlock = val.eval(page);
+    if (valUncastBlock.areAllValuesNull()) {
+      return Block.constantNullBlock(page.getPositionCount());
+    }
+    DoubleBlock valBlock = (DoubleBlock) valUncastBlock;
+    DoubleVector valVector = valBlock.asVector();
+    if (valVector == null) {
+      return eval(page.getPositionCount(), valBlock);
+    }
+    return eval(page.getPositionCount(), valVector).asBlock();
+  }
+
+  public DoubleBlock eval(int positionCount, DoubleBlock valBlock) {
+    DoubleBlock.Builder result = DoubleBlock.newBlockBuilder(positionCount);
+    position: for (int p = 0; p < positionCount; p++) {
+      if (valBlock.isNull(p) || valBlock.getValueCount(p) != 1) {
+        result.appendNull();
+        continue position;
+      }
+      result.appendDouble(Acos.process(valBlock.getDouble(valBlock.getFirstValueIndex(p))));
+    }
+    return result.build();
+  }
+
+  public DoubleVector eval(int positionCount, DoubleVector valVector) {
+    DoubleVector.Builder result = DoubleVector.newVectorBuilder(positionCount);
+    position: for (int p = 0; p < positionCount; p++) {
+      result.appendDouble(Acos.process(valVector.getDouble(p)));
+    }
+    return result.build();
+  }
+
+  @Override
+  public String toString() {
+    return "AcosEvaluator[" + "val=" + val + "]";
+  }
+}

+ 64 - 0
x-pack/plugin/esql/src/main/java/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinEvaluator.java

@@ -0,0 +1,64 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License
+// 2.0; you may not use this file except in compliance with the Elastic License
+// 2.0.
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.DoubleVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.EvalOperator;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Asin}.
+ * This class is generated. Do not edit it.
+ */
+public final class AsinEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final EvalOperator.ExpressionEvaluator val;
+
+  public AsinEvaluator(EvalOperator.ExpressionEvaluator val) {
+    this.val = val;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    Block valUncastBlock = val.eval(page);
+    if (valUncastBlock.areAllValuesNull()) {
+      return Block.constantNullBlock(page.getPositionCount());
+    }
+    DoubleBlock valBlock = (DoubleBlock) valUncastBlock;
+    DoubleVector valVector = valBlock.asVector();
+    if (valVector == null) {
+      return eval(page.getPositionCount(), valBlock);
+    }
+    return eval(page.getPositionCount(), valVector).asBlock();
+  }
+
+  public DoubleBlock eval(int positionCount, DoubleBlock valBlock) {
+    DoubleBlock.Builder result = DoubleBlock.newBlockBuilder(positionCount);
+    position: for (int p = 0; p < positionCount; p++) {
+      if (valBlock.isNull(p) || valBlock.getValueCount(p) != 1) {
+        result.appendNull();
+        continue position;
+      }
+      result.appendDouble(Asin.process(valBlock.getDouble(valBlock.getFirstValueIndex(p))));
+    }
+    return result.build();
+  }
+
+  public DoubleVector eval(int positionCount, DoubleVector valVector) {
+    DoubleVector.Builder result = DoubleVector.newVectorBuilder(positionCount);
+    position: for (int p = 0; p < positionCount; p++) {
+      result.appendDouble(Asin.process(valVector.getDouble(p)));
+    }
+    return result.build();
+  }
+
+  @Override
+  public String toString() {
+    return "AsinEvaluator[" + "val=" + val + "]";
+  }
+}

+ 80 - 0
x-pack/plugin/esql/src/main/java/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Evaluator.java

@@ -0,0 +1,80 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License
+// 2.0; you may not use this file except in compliance with the Elastic License
+// 2.0.
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.DoubleVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.EvalOperator;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Atan2}.
+ * This class is generated. Do not edit it.
+ */
+public final class Atan2Evaluator implements EvalOperator.ExpressionEvaluator {
+  private final EvalOperator.ExpressionEvaluator y;
+
+  private final EvalOperator.ExpressionEvaluator x;
+
+  public Atan2Evaluator(EvalOperator.ExpressionEvaluator y, EvalOperator.ExpressionEvaluator x) {
+    this.y = y;
+    this.x = x;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    Block yUncastBlock = y.eval(page);
+    if (yUncastBlock.areAllValuesNull()) {
+      return Block.constantNullBlock(page.getPositionCount());
+    }
+    DoubleBlock yBlock = (DoubleBlock) yUncastBlock;
+    Block xUncastBlock = x.eval(page);
+    if (xUncastBlock.areAllValuesNull()) {
+      return Block.constantNullBlock(page.getPositionCount());
+    }
+    DoubleBlock xBlock = (DoubleBlock) xUncastBlock;
+    DoubleVector yVector = yBlock.asVector();
+    if (yVector == null) {
+      return eval(page.getPositionCount(), yBlock, xBlock);
+    }
+    DoubleVector xVector = xBlock.asVector();
+    if (xVector == null) {
+      return eval(page.getPositionCount(), yBlock, xBlock);
+    }
+    return eval(page.getPositionCount(), yVector, xVector).asBlock();
+  }
+
+  public DoubleBlock eval(int positionCount, DoubleBlock yBlock, DoubleBlock xBlock) {
+    DoubleBlock.Builder result = DoubleBlock.newBlockBuilder(positionCount);
+    position: for (int p = 0; p < positionCount; p++) {
+      if (yBlock.isNull(p) || yBlock.getValueCount(p) != 1) {
+        result.appendNull();
+        continue position;
+      }
+      if (xBlock.isNull(p) || xBlock.getValueCount(p) != 1) {
+        result.appendNull();
+        continue position;
+      }
+      result.appendDouble(Atan2.process(yBlock.getDouble(yBlock.getFirstValueIndex(p)), xBlock.getDouble(xBlock.getFirstValueIndex(p))));
+    }
+    return result.build();
+  }
+
+  public DoubleVector eval(int positionCount, DoubleVector yVector, DoubleVector xVector) {
+    DoubleVector.Builder result = DoubleVector.newVectorBuilder(positionCount);
+    position: for (int p = 0; p < positionCount; p++) {
+      result.appendDouble(Atan2.process(yVector.getDouble(p), xVector.getDouble(p)));
+    }
+    return result.build();
+  }
+
+  @Override
+  public String toString() {
+    return "Atan2Evaluator[" + "y=" + y + ", x=" + x + "]";
+  }
+}

+ 64 - 0
x-pack/plugin/esql/src/main/java/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanEvaluator.java

@@ -0,0 +1,64 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License
+// 2.0; you may not use this file except in compliance with the Elastic License
+// 2.0.
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.DoubleVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.EvalOperator;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Atan}.
+ * This class is generated. Do not edit it.
+ */
+public final class AtanEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final EvalOperator.ExpressionEvaluator val;
+
+  public AtanEvaluator(EvalOperator.ExpressionEvaluator val) {
+    this.val = val;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    Block valUncastBlock = val.eval(page);
+    if (valUncastBlock.areAllValuesNull()) {
+      return Block.constantNullBlock(page.getPositionCount());
+    }
+    DoubleBlock valBlock = (DoubleBlock) valUncastBlock;
+    DoubleVector valVector = valBlock.asVector();
+    if (valVector == null) {
+      return eval(page.getPositionCount(), valBlock);
+    }
+    return eval(page.getPositionCount(), valVector).asBlock();
+  }
+
+  public DoubleBlock eval(int positionCount, DoubleBlock valBlock) {
+    DoubleBlock.Builder result = DoubleBlock.newBlockBuilder(positionCount);
+    position: for (int p = 0; p < positionCount; p++) {
+      if (valBlock.isNull(p) || valBlock.getValueCount(p) != 1) {
+        result.appendNull();
+        continue position;
+      }
+      result.appendDouble(Atan.process(valBlock.getDouble(valBlock.getFirstValueIndex(p))));
+    }
+    return result.build();
+  }
+
+  public DoubleVector eval(int positionCount, DoubleVector valVector) {
+    DoubleVector.Builder result = DoubleVector.newVectorBuilder(positionCount);
+    position: for (int p = 0; p < positionCount; p++) {
+      result.appendDouble(Atan.process(valVector.getDouble(p)));
+    }
+    return result.build();
+  }
+
+  @Override
+  public String toString() {
+    return "AtanEvaluator[" + "val=" + val + "]";
+  }
+}

+ 8 - 0
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java

@@ -33,6 +33,10 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc;
 import org.elasticsearch.xpack.esql.expression.function.scalar.date.Now;
 import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch;
 import org.elasticsearch.xpack.esql.expression.function.scalar.math.Abs;
+import org.elasticsearch.xpack.esql.expression.function.scalar.math.Acos;
+import org.elasticsearch.xpack.esql.expression.function.scalar.math.Asin;
+import org.elasticsearch.xpack.esql.expression.function.scalar.math.Atan;
+import org.elasticsearch.xpack.esql.expression.function.scalar.math.Atan2;
 import org.elasticsearch.xpack.esql.expression.function.scalar.math.AutoBucket;
 import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cos;
 import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cosh;
@@ -96,6 +100,10 @@ public class EsqlFunctionRegistry extends FunctionRegistry {
             // math
             new FunctionDefinition[] {
                 def(Abs.class, Abs::new, "abs"),
+                def(Acos.class, Acos::new, "acos"),
+                def(Asin.class, Asin::new, "asin"),
+                def(Atan.class, Atan::new, "atan"),
+                def(Atan2.class, Atan2::new, "atan2"),
                 def(AutoBucket.class, AutoBucket::new, "auto_bucket"),
                 def(Cos.class, Cos::new, "cos"),
                 def(Cosh.class, Cosh::new, "cosh"),

+ 45 - 0
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Acos.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import org.elasticsearch.compute.ann.Evaluator;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.xpack.ql.expression.Expression;
+import org.elasticsearch.xpack.ql.tree.NodeInfo;
+import org.elasticsearch.xpack.ql.tree.Source;
+
+import java.util.List;
+
+/**
+ * Inverse cosine trigonometric function.
+ */
+public class Acos extends AbstractTrigonometricFunction {
+    public Acos(Source source, Expression field) {
+        super(source, field);
+    }
+
+    @Override
+    protected EvalOperator.ExpressionEvaluator doubleEvaluator(EvalOperator.ExpressionEvaluator field) {
+        return new AcosEvaluator(field);
+    }
+
+    @Override
+    public Expression replaceChildren(List<Expression> newChildren) {
+        return new Acos(source(), newChildren.get(0));
+    }
+
+    @Override
+    protected NodeInfo<? extends Expression> info() {
+        return NodeInfo.create(this, Acos::new, field());
+    }
+
+    @Evaluator
+    static double process(double val) {
+        return Math.acos(val);
+    }
+}

+ 45 - 0
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Asin.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import org.elasticsearch.compute.ann.Evaluator;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.xpack.ql.expression.Expression;
+import org.elasticsearch.xpack.ql.tree.NodeInfo;
+import org.elasticsearch.xpack.ql.tree.Source;
+
+import java.util.List;
+
+/**
+ * Inverse cosine trigonometric function.
+ */
+public class Asin extends AbstractTrigonometricFunction {
+    public Asin(Source source, Expression field) {
+        super(source, field);
+    }
+
+    @Override
+    protected EvalOperator.ExpressionEvaluator doubleEvaluator(EvalOperator.ExpressionEvaluator field) {
+        return new AsinEvaluator(field);
+    }
+
+    @Override
+    public Expression replaceChildren(List<Expression> newChildren) {
+        return new Asin(source(), newChildren.get(0));
+    }
+
+    @Override
+    protected NodeInfo<? extends Expression> info() {
+        return NodeInfo.create(this, Asin::new, field());
+    }
+
+    @Evaluator
+    static double process(double val) {
+        return Math.asin(val);
+    }
+}

+ 45 - 0
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import org.elasticsearch.compute.ann.Evaluator;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.xpack.ql.expression.Expression;
+import org.elasticsearch.xpack.ql.tree.NodeInfo;
+import org.elasticsearch.xpack.ql.tree.Source;
+
+import java.util.List;
+
+/**
+ * Inverse cosine trigonometric function.
+ */
+public class Atan extends AbstractTrigonometricFunction {
+    public Atan(Source source, Expression field) {
+        super(source, field);
+    }
+
+    @Override
+    protected EvalOperator.ExpressionEvaluator doubleEvaluator(EvalOperator.ExpressionEvaluator field) {
+        return new AtanEvaluator(field);
+    }
+
+    @Override
+    public Expression replaceChildren(List<Expression> newChildren) {
+        return new Atan(source(), newChildren.get(0));
+    }
+
+    @Override
+    protected NodeInfo<? extends Expression> info() {
+        return NodeInfo.create(this, Atan::new, field());
+    }
+
+    @Evaluator
+    static double process(double val) {
+        return Math.atan(val);
+    }
+}

+ 106 - 0
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2.java

@@ -0,0 +1,106 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import org.elasticsearch.compute.ann.Evaluator;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.xpack.esql.planner.Mappable;
+import org.elasticsearch.xpack.ql.expression.Expression;
+import org.elasticsearch.xpack.ql.expression.Expressions;
+import org.elasticsearch.xpack.ql.expression.TypeResolutions;
+import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction;
+import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate;
+import org.elasticsearch.xpack.ql.tree.NodeInfo;
+import org.elasticsearch.xpack.ql.tree.Source;
+import org.elasticsearch.xpack.ql.type.DataType;
+import org.elasticsearch.xpack.ql.type.DataTypes;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric;
+
+/**
+ * Inverse cosine trigonometric function.
+ */
+public class Atan2 extends ScalarFunction implements Mappable {
+    private final Expression y;
+    private final Expression x;
+
+    public Atan2(Source source, Expression y, Expression x) {
+        super(source, List.of(y, x));
+        this.y = y;
+        this.x = x;
+    }
+
+    @Override
+    public Expression replaceChildren(List<Expression> newChildren) {
+        return new Atan2(source(), newChildren.get(0), newChildren.get(1));
+    }
+
+    @Override
+    protected NodeInfo<? extends Expression> info() {
+        return NodeInfo.create(this, Atan2::new, y, x);
+    }
+
+    @Evaluator
+    static double process(double y, double x) {
+        return Math.atan2(y, x);
+    }
+
+    @Override
+    public DataType dataType() {
+        return DataTypes.DOUBLE;
+    }
+
+    @Override
+    protected TypeResolution resolveType() {
+        if (childrenResolved() == false) {
+            return new TypeResolution("Unresolved children");
+        }
+
+        TypeResolution resolution = isNumeric(y, sourceText(), TypeResolutions.ParamOrdinal.FIRST);
+        if (resolution.unresolved()) {
+            return resolution;
+        }
+        return isNumeric(x, sourceText(), TypeResolutions.ParamOrdinal.SECOND);
+    }
+
+    @Override
+    public boolean foldable() {
+        return Expressions.foldable(children());
+    }
+
+    @Override
+    public Supplier<EvalOperator.ExpressionEvaluator> toEvaluator(
+        Function<Expression, Supplier<EvalOperator.ExpressionEvaluator>> toEvaluator
+    ) {
+        Supplier<EvalOperator.ExpressionEvaluator> yEval = Cast.cast(y.dataType(), DataTypes.DOUBLE, toEvaluator.apply(y));
+        Supplier<EvalOperator.ExpressionEvaluator> xEval = Cast.cast(x.dataType(), DataTypes.DOUBLE, toEvaluator.apply(x));
+        return () -> new Atan2Evaluator(yEval.get(), xEval.get());
+    }
+
+    @Override
+    public Object fold() {
+        return Mappable.super.fold();
+    }
+
+    @Override
+    public ScriptTemplate asScript() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Expression y() {
+        return y;
+    }
+
+    public Expression x() {
+        return x;
+    }
+}

+ 20 - 0
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java

@@ -44,6 +44,10 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc;
 import org.elasticsearch.xpack.esql.expression.function.scalar.date.Now;
 import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch;
 import org.elasticsearch.xpack.esql.expression.function.scalar.math.Abs;
+import org.elasticsearch.xpack.esql.expression.function.scalar.math.Acos;
+import org.elasticsearch.xpack.esql.expression.function.scalar.math.Asin;
+import org.elasticsearch.xpack.esql.expression.function.scalar.math.Atan;
+import org.elasticsearch.xpack.esql.expression.function.scalar.math.Atan2;
 import org.elasticsearch.xpack.esql.expression.function.scalar.math.AutoBucket;
 import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cos;
 import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cosh;
@@ -279,6 +283,9 @@ public final class PlanNamedTypes {
             of(QL_UNARY_SCLR_CLS, IsNull.class, PlanNamedTypes::writeQLUnaryScalar, PlanNamedTypes::readQLUnaryScalar),
             of(QL_UNARY_SCLR_CLS, Not.class, PlanNamedTypes::writeQLUnaryScalar, PlanNamedTypes::readQLUnaryScalar),
             of(ESQL_UNARY_SCLR_CLS, Abs.class, PlanNamedTypes::writeESQLUnaryScalar, PlanNamedTypes::readESQLUnaryScalar),
+            of(ESQL_UNARY_SCLR_CLS, Acos.class, PlanNamedTypes::writeESQLUnaryScalar, PlanNamedTypes::readESQLUnaryScalar),
+            of(ESQL_UNARY_SCLR_CLS, Asin.class, PlanNamedTypes::writeESQLUnaryScalar, PlanNamedTypes::readESQLUnaryScalar),
+            of(ESQL_UNARY_SCLR_CLS, Atan.class, PlanNamedTypes::writeESQLUnaryScalar, PlanNamedTypes::readESQLUnaryScalar),
             of(ESQL_UNARY_SCLR_CLS, Cos.class, PlanNamedTypes::writeESQLUnaryScalar, PlanNamedTypes::readESQLUnaryScalar),
             of(ESQL_UNARY_SCLR_CLS, Cosh.class, PlanNamedTypes::writeESQLUnaryScalar, PlanNamedTypes::readESQLUnaryScalar),
             of(ESQL_UNARY_SCLR_CLS, Floor.class, PlanNamedTypes::writeESQLUnaryScalar, PlanNamedTypes::readESQLUnaryScalar),
@@ -302,6 +309,7 @@ public final class PlanNamedTypes {
             of(ESQL_UNARY_SCLR_CLS, ToVersion.class, PlanNamedTypes::writeESQLUnaryScalar, PlanNamedTypes::readESQLUnaryScalar),
             of(ESQL_UNARY_SCLR_CLS, Trim.class, PlanNamedTypes::writeESQLUnaryScalar, PlanNamedTypes::readESQLUnaryScalar),
             // ScalarFunction
+            of(ScalarFunction.class, Atan2.class, PlanNamedTypes::writeAtan2, PlanNamedTypes::readAtan2),
             of(ScalarFunction.class, AutoBucket.class, PlanNamedTypes::writeAutoBucket, PlanNamedTypes::readAutoBucket),
             of(ScalarFunction.class, Case.class, PlanNamedTypes::writeCase, PlanNamedTypes::readCase),
             of(ScalarFunction.class, CIDRMatch.class, PlanNamedTypes::writeCIDRMatch, PlanNamedTypes::readCIDRMatch),
@@ -995,6 +1003,9 @@ public final class PlanNamedTypes {
 
     static final Map<String, BiFunction<Source, Expression, UnaryScalarFunction>> ESQL_UNARY_SCALAR_CTRS = Map.ofEntries(
         entry(name(Abs.class), Abs::new),
+        entry(name(Acos.class), Acos::new),
+        entry(name(Asin.class), Asin::new),
+        entry(name(Atan.class), Atan::new),
         entry(name(Cos.class), Cos::new),
         entry(name(Cosh.class), Cosh::new),
         entry(name(Floor.class), Floor::new),
@@ -1072,6 +1083,15 @@ public final class PlanNamedTypes {
 
     // -- ScalarFunction
 
+    static Atan2 readAtan2(PlanStreamInput in) throws IOException {
+        return new Atan2(Source.EMPTY, in.readExpression(), in.readExpression());
+    }
+
+    static void writeAtan2(PlanStreamOutput out, Atan2 atan2) throws IOException {
+        out.writeExpression(atan2.y());
+        out.writeExpression(atan2.x());
+    }
+
     static AutoBucket readAutoBucket(PlanStreamInput in) throws IOException {
         return new AutoBucket(Source.EMPTY, in.readExpression(), in.readExpression(), in.readExpression(), in.readExpression());
     }

+ 53 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosTests.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase;
+import org.elasticsearch.xpack.ql.expression.Expression;
+import org.elasticsearch.xpack.ql.tree.Source;
+import org.elasticsearch.xpack.ql.type.DataType;
+import org.elasticsearch.xpack.ql.type.DataTypes;
+import org.hamcrest.Matcher;
+
+import java.util.List;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class AcosTests extends AbstractScalarFunctionTestCase {
+    @Override
+    protected TestCase getSimpleTestCase() {
+        double d = randomDouble();
+        List<TypedData> typedData = List.of(new TypedData(d, DataTypes.DOUBLE, "arg"));
+        return new TestCase(Source.EMPTY, typedData, equalTo(Math.acos(d)));
+    }
+
+    @Override
+    protected DataType expectedType(List<DataType> argTypes) {
+        return DataTypes.DOUBLE;
+    }
+
+    @Override
+    protected Matcher<Object> resultMatcher(List<Object> data, DataType dataType) {
+        return equalTo(Math.acos(((Number) data.get(0)).doubleValue()));
+    }
+
+    @Override
+    protected String expectedEvaluatorSimpleToString() {
+        return "AcosEvaluator[val=Attribute[channel=0]]";
+    }
+
+    @Override
+    protected List<ArgumentSpec> argSpec() {
+        return List.of(required(numerics()));
+    }
+
+    @Override
+    protected Expression build(Source source, List<Expression> args) {
+        return new Acos(source, args.get(0));
+    }
+}

+ 53 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinTests.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase;
+import org.elasticsearch.xpack.ql.expression.Expression;
+import org.elasticsearch.xpack.ql.tree.Source;
+import org.elasticsearch.xpack.ql.type.DataType;
+import org.elasticsearch.xpack.ql.type.DataTypes;
+import org.hamcrest.Matcher;
+
+import java.util.List;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class AsinTests extends AbstractScalarFunctionTestCase {
+    @Override
+    protected TestCase getSimpleTestCase() {
+        double d = randomDouble();
+        List<TypedData> typedData = List.of(new TypedData(d, DataTypes.DOUBLE, "arg"));
+        return new TestCase(Source.EMPTY, typedData, equalTo(Math.asin(d)));
+    }
+
+    @Override
+    protected DataType expectedType(List<DataType> argTypes) {
+        return DataTypes.DOUBLE;
+    }
+
+    @Override
+    protected Matcher<Object> resultMatcher(List<Object> data, DataType dataType) {
+        return equalTo(Math.asin(((Number) data.get(0)).doubleValue()));
+    }
+
+    @Override
+    protected String expectedEvaluatorSimpleToString() {
+        return "AsinEvaluator[val=Attribute[channel=0]]";
+    }
+
+    @Override
+    protected List<ArgumentSpec> argSpec() {
+        return List.of(required(numerics()));
+    }
+
+    @Override
+    protected Expression build(Source source, List<Expression> args) {
+        return new Asin(source, args.get(0));
+    }
+}

+ 54 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Tests.java

@@ -0,0 +1,54 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase;
+import org.elasticsearch.xpack.ql.expression.Expression;
+import org.elasticsearch.xpack.ql.tree.Source;
+import org.elasticsearch.xpack.ql.type.DataType;
+import org.elasticsearch.xpack.ql.type.DataTypes;
+import org.hamcrest.Matcher;
+
+import java.util.List;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class Atan2Tests extends AbstractScalarFunctionTestCase {
+    @Override
+    protected TestCase getSimpleTestCase() {
+        double y = randomDoubleBetween(Double.MIN_VALUE, Double.MAX_VALUE, true);
+        double x = randomDoubleBetween(Double.MIN_VALUE, Double.MAX_VALUE, true);
+        List<TypedData> typedData = List.of(new TypedData(y, DataTypes.DOUBLE, "y"), new TypedData(x, DataTypes.DOUBLE, "x"));
+        return new TestCase(Source.EMPTY, typedData, equalTo(Math.atan2(y, x)));
+    }
+
+    @Override
+    protected DataType expectedType(List<DataType> argTypes) {
+        return DataTypes.DOUBLE;
+    }
+
+    @Override
+    protected Matcher<Object> resultMatcher(List<Object> data, DataType dataType) {
+        return equalTo(Math.atan2(((Number) data.get(0)).doubleValue(), ((Number) data.get(1)).doubleValue()));
+    }
+
+    @Override
+    protected String expectedEvaluatorSimpleToString() {
+        return "Atan2Evaluator[y=Attribute[channel=0], x=Attribute[channel=1]]";
+    }
+
+    @Override
+    protected List<ArgumentSpec> argSpec() {
+        return List.of(required(numerics()), required(numerics()));
+    }
+
+    @Override
+    protected Expression build(Source source, List<Expression> args) {
+        return new Atan2(source, args.get(0), args.get(1));
+    }
+}

+ 53 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanTests.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase;
+import org.elasticsearch.xpack.ql.expression.Expression;
+import org.elasticsearch.xpack.ql.tree.Source;
+import org.elasticsearch.xpack.ql.type.DataType;
+import org.elasticsearch.xpack.ql.type.DataTypes;
+import org.hamcrest.Matcher;
+
+import java.util.List;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class AtanTests extends AbstractScalarFunctionTestCase {
+    @Override
+    protected TestCase getSimpleTestCase() {
+        double d = randomDoubleBetween(Double.MIN_VALUE, Double.MAX_VALUE, true);
+        List<TypedData> typedData = List.of(new TypedData(d, DataTypes.DOUBLE, "arg"));
+        return new TestCase(Source.EMPTY, typedData, equalTo(Math.atan(d)));
+    }
+
+    @Override
+    protected DataType expectedType(List<DataType> argTypes) {
+        return DataTypes.DOUBLE;
+    }
+
+    @Override
+    protected Matcher<Object> resultMatcher(List<Object> data, DataType dataType) {
+        return equalTo(Math.atan(((Number) data.get(0)).doubleValue()));
+    }
+
+    @Override
+    protected String expectedEvaluatorSimpleToString() {
+        return "AtanEvaluator[val=Attribute[channel=0]]";
+    }
+
+    @Override
+    protected List<ArgumentSpec> argSpec() {
+        return List.of(required(numerics()));
+    }
+
+    @Override
+    protected Expression build(Source source, List<Expression> args) {
+        return new Atan(source, args.get(0));
+    }
+}