From 0da0876d449c89007e3c506c4bb6950e1256b419 Mon Sep 17 00:00:00 2001 From: Mohsen Taheri Shalmani Date: Mon, 25 Aug 2025 11:24:55 +0200 Subject: [PATCH 1/7] Updating encoder and AI models to handell null values Encoder is updated to handle null values The models are applied on three SUT 1. NCS API from EMB 2. Basic API 3. Multitype API --- .../basic/BasicApplication.kt | 46 +++++ .../multitype/MultiTypeApplication.kt} | 6 +- .../aiclassification/ncs/NCSApplication.kt | 174 ++++++++++++++++++ .../aiclassification/ncs/imp/Bessj.java | 119 ++++++++++++ .../spring/aiclassification/ncs/imp/Dto.java | 8 + .../aiclassification/ncs/imp/Expint.java | 76 ++++++++ .../aiclassification/ncs/imp/Fisher.java | 63 +++++++ .../aiclassification/ncs/imp/Gammq.java | 92 +++++++++ .../aiclassification/ncs/imp/Remainder.java | 42 +++++ .../ncs/imp/TriangleClassification.java | 29 +++ .../aiclassification/basic/BasicController.kt | 6 + .../multitype/MultiTypeController.kt | 6 + .../aiclassification/ncs/NCSController.kt | 6 + .../numeric/AICMultiTypeController.kt | 5 - .../AIGLMCheck.kt | 22 ++- .../AIGaussianCheck.kt | 27 ++- .../rest/classifier/InputEncoderUtils.kt | 33 +++- 17 files changed, 726 insertions(+), 34 deletions(-) create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/basic/BasicApplication.kt rename core-it/src/main/kotlin/bar/examples/it/spring/{aiconstraint/numeric/AICMultiTypeApplication.kt => aiclassification/multitype/MultiTypeApplication.kt} (97%) create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSApplication.kt create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Bessj.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Dto.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Expint.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Fisher.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Gammq.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Remainder.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/TriangleClassification.java create mode 100644 core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/basic/BasicController.kt create mode 100644 core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/multitype/MultiTypeController.kt create mode 100644 core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSController.kt delete mode 100644 core-it/src/test/kotlin/bar/examples/it/spring/aiconstraint/numeric/AICMultiTypeController.kt rename core-it/src/test/kotlin/org/evomaster/core/problem/rest/{aiconstraint/numeric => aiclassification}/AIGLMCheck.kt (92%) rename core-it/src/test/kotlin/org/evomaster/core/problem/rest/{aiconstraint/numeric => aiclassification}/AIGaussianCheck.kt (90%) diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/basic/BasicApplication.kt b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/basic/BasicApplication.kt new file mode 100644 index 0000000000..d3086c3514 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/basic/BasicApplication.kt @@ -0,0 +1,46 @@ +package bar.examples.it.spring.aiclassification.basic + +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import javax.ws.rs.QueryParam + +@SpringBootApplication(exclude = [SecurityAutoConfiguration::class]) +@RequestMapping(path = ["/api/basic"]) +@RestController +open class BasicApplication { + + companion object { + @JvmStatic + fun main(args: Array) { + SpringApplication.run(BasicApplication::class.java, *args) + } + } + + enum class Alphabet { + A, + B, + C, + D + } + + @GetMapping + open fun getData( + @RequestParam("x", required = false) x: Alphabet?, + @RequestParam("y", required = false) y: Int?, + @RequestParam("z", required = false) z: Boolean?, + ): ResponseEntity { + + // No dependency, just constraint on a single variable + if (y == null) { + return ResponseEntity.status(400).build() + } + + return ResponseEntity.ok().body("OK") + } +} \ No newline at end of file diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiconstraint/numeric/AICMultiTypeApplication.kt b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/multitype/MultiTypeApplication.kt similarity index 97% rename from core-it/src/main/kotlin/bar/examples/it/spring/aiconstraint/numeric/AICMultiTypeApplication.kt rename to core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/multitype/MultiTypeApplication.kt index 1d2db37ba5..1bc13ac038 100644 --- a/core-it/src/main/kotlin/bar/examples/it/spring/aiconstraint/numeric/AICMultiTypeApplication.kt +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/multitype/MultiTypeApplication.kt @@ -1,4 +1,4 @@ -package bar.examples.it.spring.aiconstraint.numeric +package bar.examples.it.spring.aiclassification.multitype import io.swagger.v3.oas.annotations.Parameter import org.springframework.boot.SpringApplication @@ -10,12 +10,12 @@ import org.springframework.web.bind.annotation.* @SpringBootApplication(exclude = [SecurityAutoConfiguration::class]) @RequestMapping(path = ["/petShopApi"]) @RestController -open class AICMultiTypeApplication { +open class MultiTypeApplication { companion object { @JvmStatic fun main(args: Array) { - SpringApplication.run(AICMultiTypeApplication::class.java, *args) + SpringApplication.run(MultiTypeApplication::class.java, *args) } } diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSApplication.kt b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSApplication.kt new file mode 100644 index 0000000000..e0d9957117 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSApplication.kt @@ -0,0 +1,174 @@ +package bar.examples.it.spring.aiclassification.ncs + +import bar.examples.it.spring.aiclassification.ncs.imp.Bessj +import bar.examples.it.spring.aiclassification.ncs.imp.Dto +import bar.examples.it.spring.aiclassification.ncs.imp.Expint +import bar.examples.it.spring.aiclassification.ncs.imp.Fisher +import bar.examples.it.spring.aiclassification.ncs.imp.Gammq +import bar.examples.it.spring.aiclassification.ncs.imp.Remainder +import bar.examples.it.spring.aiclassification.ncs.imp.TriangleClassification +import io.swagger.v3.oas.annotations.Parameter +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@SpringBootApplication(exclude = [SecurityAutoConfiguration::class]) +@RestController +@RequestMapping(path = ["/api"]) +open class NCSApplication { + + companion object { + @JvmStatic + fun main(args: Array) { + SpringApplication.run(NCSApplication::class.java, *args) + } + } + + @GetMapping( + value = ["/triangle/{a}/{b}/{c}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun checkTriangle( + @PathVariable("a") + @Parameter(description = "First edge", required = true) + a: Int, + + @PathVariable("b") + @Parameter(description = "Second edge", required = true) + b: Int, + + @PathVariable("c") + @Parameter(description = "Third edge", required = true) + c: Int + ): ResponseEntity { + + val dto = Dto() + dto.resultAsInt = TriangleClassification.classify(a, b, c) + return ResponseEntity.ok(dto) + } + + @GetMapping( + value = ["/bessj/{n}/{x}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun bessj( + @PathVariable("n") + @Parameter(description = "Order n (2 < n ≤ 1000)", required = true) + n: Int, + + @PathVariable("x") + @Parameter(description = "Argument x", required = true) + x: Double + ): ResponseEntity { + if (n <= 2 || n > 1000) { + return ResponseEntity.status(400).build() + } + + val dto = Dto() + val bessj = Bessj() + dto.resultAsDouble = bessj.bessj(n, x) + return ResponseEntity.ok(dto) + } + + @GetMapping( + value = ["/expint/{n}/{x}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun expint( + @PathVariable("n") + @Parameter(description = "Order n", required = true) + n: Int, + + @PathVariable("x") + @Parameter(description = "Argument x", required = true) + x: Double + ): ResponseEntity = + try { + val dto = Dto() + dto.resultAsDouble = Expint.exe(n, x) + ResponseEntity.ok(dto) + } catch (e: RuntimeException) { + ResponseEntity.status(400).build() + } + + @GetMapping( + value = ["/fisher/{m}/{n}/{x}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun fisher( + @PathVariable("m") + @Parameter(description = "Degrees of freedom m (≤ 1000)", required = true) + m: Int, + + @PathVariable("n") + @Parameter(description = "Degrees of freedom n (≤ 1000)", required = true) + n: Int, + + @PathVariable("x") + @Parameter(description = "Argument x", required = true) + x: Double + ): ResponseEntity { + if (m > 1000 || n > 1000) { + return ResponseEntity.status(400).build() + } + + return try { + val dto = Dto() + dto.resultAsDouble = Fisher.exe(m, n, x) + ResponseEntity.ok(dto) + } catch (e: RuntimeException) { + ResponseEntity.status(400).build() + } + } + + @GetMapping( + value = ["/gammq/{a}/{x}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun gammq( + @PathVariable("a") + @Parameter(description = "Shape a", required = true) + a: Double, + + @PathVariable("x") + @Parameter(description = "Argument x", required = true) + x: Double + ): ResponseEntity = + try { + val dto = Dto() + val gammq = Gammq() + dto.resultAsDouble = gammq.exe(a, x) + ResponseEntity.ok(dto) + } catch (e: RuntimeException) { + ResponseEntity.status(400).build() + } + + @GetMapping( + value = ["/remainder/{a}/{b}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun remainder( + @PathVariable("a") + @Parameter(description = "Dividend a (|a| ≤ 10000)", required = true) + a: Int, + + @PathVariable("b") + @Parameter(description = "Divisor b (|b| ≤ 10000)", required = true) + b: Int + ): ResponseEntity { + val lim = 10_000 + if (a > lim || a < -lim || b > lim || b < -lim) { + return ResponseEntity.status(400).build() + } + + val dto = Dto() + dto.resultAsInt = Remainder.exe(a, b) + return ResponseEntity.ok(dto) + } +} \ No newline at end of file diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Bessj.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Bessj.java new file mode 100644 index 0000000000..45d5a6e571 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Bessj.java @@ -0,0 +1,119 @@ +package bar.examples.it.spring.aiclassification.ncs.imp; + +public class Bessj { + + private final double ACC = 40.0; + private final double BIGNO = 1.0e10; + private final double BIGNI = 1.0e-10; + + public double bessj(int n, double x) { + int j, jsum, m; + double ax, bj, bjm, bjp, sum, tox, ans; + + if (n < 2) + throw new IllegalArgumentException("Index n less than 2 in bessj"); + + ax = Math.abs(x); + + if (ax == 0.0) + return 0.0; + else if (ax > n) { + tox = 2.0 / ax; + bjm = bessj0(ax); + bj = bessj1(ax); + + for (j = 1; j < n; j++) { + bjp = j * tox * bj - bjm; + bjm = bj; + bj = bjp; + } + + ans = bj; + } else { + tox = 2.0 / ax; + m = 2 * ((n + (int) Math.round(Math.sqrt(ACC * n))) / 2); + jsum = 0; + bjp = ans = sum = 0.0; + bj = 1.0; + + for (j = m; j > 0; j--) { + bjm = j * tox * bj - bjp; + bjp = bj; + bj = bjm; + + if (Math.abs(bj) > BIGNO) { + bj *= BIGNI; + bjp *= BIGNI; + ans *= BIGNI; + sum *= BIGNI; + } + + if (jsum != 0) + sum += bj; + + jsum = (jsum != 0) ? 0 : 1; + + if (j == n) + ans = bjp; + } + + sum = 2.0 * sum - bj; + ans /= sum; + } + return x < 0.0 && (n & 1) != 0 ? -ans : ans; + } + + + private static double bessj0(double x) { + double ax, z; + double xx, y, ans, ans1, ans2; + + if ((ax = Math.abs(x)) < 8.0) { + y = x * x; + ans1 = 57568490574.0 + y * (-13362590354.0 + y * (651619640.7 + + y * (-11214424.18 + y * (77392.33017 + y * (-184.9052456))))); + ans2 = 57568490411.0 + y * (1029532985.0 + y * (9494680.718 + + y * (59272.64853 + y * (267.8532712 + y * 1.0)))); + ans = ans1 / ans2; + } else { + z = 8.0 / ax; + y = z * z; + xx = ax - 0.785398164; + ans1 = 1.0 + y * (-0.1098628627e-2 + y * (0.2734510407e-4 + + y * (-0.2073370639e-5 + y * 0.2093887211e-6))); + ans2 = -0.1562499995e-1 + y * (0.1430488765e-3 + + y * (-0.6911147651e-5 + y * (0.7621095161e-6 + - y * 0.934935152e-7))); + ans = Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2); + } + return ans; + } + + + private static double bessj1(double x) { + double ax, z; + double xx, y, ans, ans1, ans2; + + if ((ax = Math.abs(x)) < 8.0) { + y = x * x; + ans1 = x * (72362614232.0 + y * (-7895059235.0 + y * (242396853.1 + + y * (-2972611.439 + y * (15704.48260 + y * (-30.16036606)))))); + ans2 = 144725228442.0 + y * (2300535178.0 + y * (18583304.74 + + y * (99447.43394 + y * (376.9991397 + y * 1.0)))); + ans = ans1 / ans2; + } else { + z = 8.0 / ax; + y = z * z; + xx = ax - 2.356194491; + ans1 = 1.0 + y * (0.183105e-2 + y * (-0.3516396496e-4 + + y * (0.2457520174e-5 + y * (-0.240337019e-6)))); + ans2 = 0.04687499995 + y * (-0.2002690873e-3 + + y * (0.8449199096e-5 + y * (-0.88228987e-6 + + y * 0.105787412e-6))); + ans = Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2); + if (x < 0.0) ans = -ans; + } + + return ans; + } +} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Dto.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Dto.java new file mode 100644 index 0000000000..576a341094 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Dto.java @@ -0,0 +1,8 @@ +package bar.examples.it.spring.aiclassification.ncs.imp; + +public class Dto { + + public Integer resultAsInt; + + public Double resultAsDouble; +} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Expint.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Expint.java new file mode 100644 index 0000000000..e7095538f3 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Expint.java @@ -0,0 +1,76 @@ +package bar.examples.it.spring.aiclassification.ncs.imp; + +public class Expint { + private static final double MAXIT = 100; + private static final double EULER = 0.5772156649; + private static final double FPMIN = 1.0e-30; + private static final double EPS = 1.0e-7; + + public static double exe(int n, double x) { + int i, ii, nm1; + double a, b, c, d, del, fact, h, psi, ans; + + nm1 = n - 1; + + if (n < 0 || x < 0.0 || (x == 0.0 && (n == 0 || n == 1))) + throw new RuntimeException("error: n < 0 or x < 0"); + else { + if (n == 0) + ans = Math.exp(-x) / x; + else { + if (x == 0.0) + ans = 1.0 / nm1; + else { + if (x > 1.0) { + b = x + n; + c = 1.0 / FPMIN; + d = 1.0 / b; + h = d; + + for (i = 1; i <= MAXIT; i++) { + a = -i * (nm1 + i); + b += 2.0; + d = 1.0 / (a * d + b); + c = b + a / c; + del = c * d; + h *= del; + + if (Math.abs(del - 1.0) < EPS) { + return h * Math.exp(-x); + } + } + + throw new RuntimeException("continued fraction failed in expint"); + } else { + ans = (nm1 != 0 ? 1.0 / nm1 : -Math.log(x) - EULER); + fact = 1.0; + + for (i = 1; i <= MAXIT; i++) { + fact *= -x / i; + + if (i != nm1) + del = -fact / (i - nm1); + else { + psi = -EULER; + + for (ii = 1; ii <= nm1; ii++) + psi += 1.0 / ii; + + del = fact * (-Math.log(x) + psi); + } + + ans += del; + + if (Math.abs(del) < Math.abs(ans) * EPS) { + return ans; + } + } + throw new RuntimeException("series failed in expint"); + } + } + } + } + return ans; + } +} + diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Fisher.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Fisher.java new file mode 100644 index 0000000000..df2f45fbfd --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Fisher.java @@ -0,0 +1,63 @@ +package bar.examples.it.spring.aiclassification.ncs.imp; + + + +public class Fisher { + public static double exe(int m, int n, double x) { + int a, b, i, j; + double w, y, z, zk, d, p; + + a = 2 * (m / 2) - m + 2; + b = 2 * (n / 2) - n + 2; + w = (x * m) / n; + z = 1.0 / (1.0 + w); + + if (a == 1) { + if (b == 1) { + p = Math.sqrt(w); + y = 0.3183098862; + d = y * z / p; + p = 2.0 * y * Math.atan(p); + } else { + p = Math.sqrt(w * z); + d = 0.5 * p * z / w; + } + } else if (b == 1) { + p = Math.sqrt(z); + d = 0.5 * z * p; + p = 1.0 - p; + } else { + d = z * z; + p = w * z; + } + + y = 2.0 * w / z; + + if (a == 1) + for (j = b + 2; j <= n; j += 2) { + d *= (1.0 + 1.0 / (j - 2)) * z; + p += d * y / (j - 1); + } + else { + zk = Math.pow(z, (double) ((n - 1) / 2)); + d *= (zk * n) / b; + p = p * zk + w * z * (zk - 1.0) / (z - 1.0); + } + + y = w * z; + z = 2.0 / z; + b = n - 2; + for (i = a + 2; i <= m; i += 2) { + j = i + b; + d *= (y * j) / (i - 2); + p -= z * d / j; + } + + if (p < 0.0) + return 0.0; + else if (p > 1.0) + return 1.0; + else + return p; + } +} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Gammq.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Gammq.java new file mode 100644 index 0000000000..7b14a70e1f --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Gammq.java @@ -0,0 +1,92 @@ +package bar.examples.it.spring.aiclassification.ncs.imp; +public class Gammq { + private static final int ITMAX = 100; + private static final double EPS = 3.0e-7; + private static final double FPMIN = 1.0e-30; + + private double gamser, gammcf, gln; + + private double gammln(double xx) { + + double x,y,tmp,ser; + + double cof[] = {76.18009172947146,-86.50532032941677,24.01409824083091,-1.231739572450155,0.1208650973866179e-2,-0.5395239384953e-5}; + + int j; + + y=x=xx; + tmp=x+5.5; + tmp -= (x+0.5)*Math.log(tmp); + ser=1.000000000190015; + for (j=0;j<=5;j++) ser += cof[j]/++y; + return -tmp+Math.log(2.5066282746310005*ser/x); + } + + private void gcf(double a, double x) + { + int i; + double an,b,c,d,del,h; + + gln=gammln(a); + b=x+1.0-a; + c=1.0/FPMIN; + d=1.0/b; + h=d; + for (i=1;i<=ITMAX;i++) { + an = -i*(i-a); + b += 2.0; + d=an*d+b; + if (Math.abs(d) < FPMIN) d=FPMIN; + c=b+an/c; + if (Math.abs(c) < FPMIN) c=FPMIN; + d=1.0/d; + del=d*c; + h *= del; + if (Math.abs(del-1.0) < EPS) break; + } + if (i > ITMAX) throw new RuntimeException ("a too large, ITMAX too small in gcf"); + gammcf=Math.exp(-x+a*Math.log(x)-gln)*h; + } + + private void gser(double a, double x) { + + int n; + double sum,del,ap; + + gln=gammln(a); + + if (x <= 0.0) { + if (x < 0.0) throw new RuntimeException ("x less than 0 in routine gser"); + gamser=0.0; + return; + } + else { + ap=a; + del=sum=1.0/a; + for (n=1;n<=ITMAX;n++) { + ++ap; + del *= x/ap; + sum += del; + if (Math.abs(del) < Math.abs(sum)*EPS) { + gamser=sum*Math.exp(-x+a*Math.log(x)-gln); + return; + } + } + throw new RuntimeException ("a too large, ITMAX too small in routine gser"); + } + } + + public double exe(double a, double x) { + if (x < 0.0 || a <= 0.0) throw new RuntimeException("Invalid arguments in routine gammq"); + if (x < (a+1.0)) { + gser(a,x); + return 1-gamser; + } + else { + gcf(a,x); + return gammcf; + } + } + +} + diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Remainder.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Remainder.java new file mode 100644 index 0000000000..faee40abc4 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Remainder.java @@ -0,0 +1,42 @@ +package bar.examples.it.spring.aiclassification.ncs.imp; + +public class Remainder { + public static int exe(int a, int b) { + int r = 0 - 1; + int cy = 0; + int ny = 0; + + if (a == 0) ; + else if (b == 0) ; + else if (a > 0) + if (b > 0) + while ((a - ny) >= b) { + ny = ny + b; + r = a - ny; + cy = cy + 1; + } + else // b<0 + //while((a+ny)>=Math.abs(b)) + while ((a + ny) >= ((b >= 0) ? b : -b)) { + ny = ny + b; + r = a + ny; + cy = cy - 1; + } + else // a<0 + if (b > 0) + //while(Math.abs(a+ny)>=b) + while (((a + ny) >= 0 ? (a + ny) : -(a + ny)) >= b) { + ny = ny + b; + r = a + ny; + cy = cy - 1; + } + else + while (b >= (a - ny)) { + ny = ny + b; + //r=Math.abs(a-ny); + r = ((a - ny) >= 0 ? (a - ny) : -(a - ny)); + cy = cy + 1; + } + return r; + } +} \ No newline at end of file diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/TriangleClassification.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/TriangleClassification.java new file mode 100644 index 0000000000..b0a9437ab2 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/TriangleClassification.java @@ -0,0 +1,29 @@ +package bar.examples.it.spring.aiclassification.ncs.imp; + +public class TriangleClassification { + + public static int classify(int a, int b, int c) { + + if (a <= 0 || b <= 0 || c <= 0) { + return 0; + } + + if (a == b && b == c) { + return 3; + } + + int max = Math.max(a, Math.max(b, c)); + + if ((max == a && max - b - c >= 0) || + (max == b && max - a - c >= 0) || + (max == c && max - a - b >= 0)) { + return 0; + } + + if (a == b || b == c || a == c) { + return 2; + } else { + return 1; + } + } +} diff --git a/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/basic/BasicController.kt b/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/basic/BasicController.kt new file mode 100644 index 0000000000..9f1fd77f99 --- /dev/null +++ b/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/basic/BasicController.kt @@ -0,0 +1,6 @@ +package bar.examples.it.spring.aiclassification.basic + +import bar.examples.it.spring.SpringController + +class BasicController : SpringController(BasicApplication::class.java) + diff --git a/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/multitype/MultiTypeController.kt b/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/multitype/MultiTypeController.kt new file mode 100644 index 0000000000..9247181a36 --- /dev/null +++ b/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/multitype/MultiTypeController.kt @@ -0,0 +1,6 @@ +package bar.examples.it.spring.aiclassification.multitype + +import bar.examples.it.spring.SpringController + +class MultiTypeController : SpringController(MultiTypeApplication::class.java) + diff --git a/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSController.kt b/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSController.kt new file mode 100644 index 0000000000..7ff02ac9d2 --- /dev/null +++ b/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSController.kt @@ -0,0 +1,6 @@ +package bar.examples.it.spring.aiclassification.ncs + +import bar.examples.it.spring.SpringController + +class NCSController : SpringController(NCSApplication::class.java) + diff --git a/core-it/src/test/kotlin/bar/examples/it/spring/aiconstraint/numeric/AICMultiTypeController.kt b/core-it/src/test/kotlin/bar/examples/it/spring/aiconstraint/numeric/AICMultiTypeController.kt deleted file mode 100644 index 0a01bdf0a8..0000000000 --- a/core-it/src/test/kotlin/bar/examples/it/spring/aiconstraint/numeric/AICMultiTypeController.kt +++ /dev/null @@ -1,5 +0,0 @@ -package bar.examples.it.spring.aiconstraint.numeric - -import bar.examples.it.spring.SpringController - -class AICMultiTypeController : SpringController(AICMultiTypeApplication::class.java) \ No newline at end of file diff --git a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiconstraint/numeric/AIGLMCheck.kt b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt similarity index 92% rename from core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiconstraint/numeric/AIGLMCheck.kt rename to core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt index 5804b0a2d7..aee0b6f83b 100644 --- a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiconstraint/numeric/AIGLMCheck.kt +++ b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt @@ -1,6 +1,8 @@ -package org.evomaster.core.problem.rest.aiconstraint.numeric +package org.evomaster.core.problem.rest.aiclassification -import bar.examples.it.spring.aiconstraint.numeric.AICMultiTypeController +import bar.examples.it.spring.aiclassification.basic.BasicController +import bar.examples.it.spring.aiclassification.multitype.MultiTypeController +import bar.examples.it.spring.aiclassification.ncs.NCSController import org.evomaster.core.problem.enterprise.SampleType import org.evomaster.core.problem.rest.IntegrationTestRestBase import org.evomaster.core.problem.rest.data.RestCallAction @@ -20,6 +22,7 @@ import org.evomaster.core.search.service.Randomness import java.net.HttpURLConnection import java.net.URL import javax.ws.rs.core.MediaType +import kotlin.collections.iterator import kotlin.math.abs @@ -28,7 +31,9 @@ class AIGLMCheck : IntegrationTestRestBase() { companion object { @JvmStatic fun init() { - initClass(AICMultiTypeController()) +// initClass(NCSController()) + initClass(BasicController()) +// initClass(MultiTypeController()) } @JvmStatic @@ -102,7 +107,7 @@ class AIGLMCheck : IntegrationTestRestBase() { val name = action.getName() val hasUnsupportedGene = action.parameters.any { p -> - val g = p.gene + val g = p.gene.getLeafGene() g !is IntegerGene && g !is DoubleGene && g !is BooleanGene && g !is EnumGene<*> } @@ -110,7 +115,7 @@ class AIGLMCheck : IntegrationTestRestBase() { null } else { action.parameters.count { p -> - val g = p.gene + val g = p.gene.getLeafGene() g is IntegerGene || g is DoubleGene || g is BooleanGene || g is EnumGene<*> } } @@ -165,7 +170,7 @@ class AIGLMCheck : IntegrationTestRestBase() { println("Classifier : ${if (classifier == null) "null" else "GLM"}") println("Dimension : $dimension") println("Input Genes : ${geneValues.joinToString(", ")}") - println("Actual Genes : ${geneValues.size}") + println("Genes Size : ${geneValues.size}") println("cp, tot, ac : $cp, $tot, $ac") // executeRestCallAction is replaced with createIndividual to avoid override error @@ -192,6 +197,7 @@ class AIGLMCheck : IntegrationTestRestBase() { } // Classification + println("Classifying!") val classification = classifier.classify(action) val p200 = classification.probabilities[200]!! val p400 = classification.probabilities[400]!! @@ -201,10 +207,11 @@ class AIGLMCheck : IntegrationTestRestBase() { // Prediction val prediction: Int = if (p200 > p400) 200 else 400 + println("Prediction is : $prediction") // Probabilistic decision-making based on Bernoulli(prob = aci) val sendOrNot: Boolean - if (prediction == 200) { + if (prediction != 400) { sendOrNot = true }else{ sendOrNot = if(Math.random() > ac) true else false @@ -225,6 +232,7 @@ class AIGLMCheck : IntegrationTestRestBase() { endpointToTotalExecution[name] = tot endpointToAccuracy[name] = ac + println("Updating the classifier!") classifier.updateModel(action, result) } diff --git a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiconstraint/numeric/AIGaussianCheck.kt b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt similarity index 90% rename from core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiconstraint/numeric/AIGaussianCheck.kt rename to core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt index 273e780cf6..e4996ef0ac 100644 --- a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiconstraint/numeric/AIGaussianCheck.kt +++ b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt @@ -1,6 +1,8 @@ -package org.evomaster.core.problem.rest.aiconstraint.numeric +package org.evomaster.core.problem.rest.aiclassification -import bar.examples.it.spring.aiconstraint.numeric.AICMultiTypeController +import bar.examples.it.spring.aiclassification.basic.BasicController +import bar.examples.it.spring.aiclassification.multitype.MultiTypeController +import bar.examples.it.spring.aiclassification.ncs.NCSController import org.evomaster.core.problem.enterprise.SampleType import org.evomaster.core.problem.rest.IntegrationTestRestBase import org.evomaster.core.problem.rest.data.RestCallAction @@ -20,6 +22,7 @@ import org.evomaster.core.search.service.Randomness import java.net.HttpURLConnection import java.net.URL import javax.ws.rs.core.MediaType +import kotlin.collections.iterator import kotlin.math.abs @@ -28,7 +31,9 @@ class AIGaussianCheck : IntegrationTestRestBase() { companion object { @JvmStatic fun init() { - initClass(AICMultiTypeController()) + initClass(NCSController()) +// initClass(BasicController()) +// initClass(MultiTypeController()) } @JvmStatic @@ -97,7 +102,8 @@ class AIGaussianCheck : IntegrationTestRestBase() { val name = action.getName() val hasUnsupportedGene = action.parameters.any { p -> - val g = p.gene + val g = p.gene.getLeafGene() + println("Parameter: ${p.name}, Gene: ${g::class.simpleName}") g !is IntegerGene && g !is DoubleGene && g !is BooleanGene && g !is EnumGene<*> } @@ -105,7 +111,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { null } else { action.parameters.count { p -> - val g = p.gene + val g = p.gene.getLeafGene() g is IntegerGene || g is DoubleGene || g is BooleanGene || g is EnumGene<*> } } @@ -142,7 +148,6 @@ class AIGaussianCheck : IntegrationTestRestBase() { val sampler = injector.getInstance(AbstractRestSampler::class.java) val startTime = System.currentTimeMillis() val runDuration = 5_000L // Milliseconds - println(" This is the start!!!!") while (System.currentTimeMillis() - startTime < runDuration) { val template = random.choose(actionList) val sampledAction = template.copy() as RestCallAction @@ -151,7 +156,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { val name = sampledAction.getName() val classifier = endpointToClassifier[name] val dimension = endpointToDimension[name] - val geneValues = sampledAction.parameters.map { it.gene.getValueAsRawString() } + val geneValues = sampledAction.parameters.map { it.gene.getValueAsRawString()} var cp = endpointToCorrectPrediction[name]!! var tot = endpointToTotalExecution[name]!! var ac = endpointToAccuracy[name]!! @@ -161,7 +166,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { println("Classifier : ${if (classifier == null) "null" else "GAUSSIAN"}") println("Dimension : $dimension") println("Input Genes : ${geneValues.joinToString(", ")}") - println("Actual Genes : ${geneValues.size}") + println("Genes Size : ${geneValues.size}") println("cp, tot, ac : $cp, $tot, $ac") // executeRestCallAction is replaced with createIndividual to avoid override error @@ -181,6 +186,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { if (isCold) { println("Warmup by at least $n request") val result = executeRestCallAction(action, "$baseUrlOfSut") + println("Response : ${result.getStatusCode()}") classifier.updateModel(action, result) tot += 1 endpointToTotalExecution[name] = tot @@ -188,6 +194,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { } // Classification + println("Classifying!") val classification = classifier.classify(action) val p200 = classification.probabilities[200]!! val p400 = classification.probabilities[400]!! @@ -197,10 +204,11 @@ class AIGaussianCheck : IntegrationTestRestBase() { // Prediction val prediction: Int = if (p200 > p400) 200 else 400 + println("Prediction is : $prediction") // Probabilistic decision-making based on Bernoulli(prob = aci) val sendOrNot: Boolean - if (prediction == 200) { + if (prediction != 400) { sendOrNot = true }else{ sendOrNot = if(Math.random() > ac) true else false @@ -221,6 +229,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { endpointToTotalExecution[name] = tot endpointToAccuracy[name] = ac + println("Updating the classifier!") classifier.updateModel(action, result) val d200 = classifier.getDensity200() diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/InputEncoderUtils.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/InputEncoderUtils.kt index 666b3e1404..42dfc169cc 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/InputEncoderUtils.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/InputEncoderUtils.kt @@ -15,12 +15,12 @@ import org.evomaster.core.search.gene.numeric.IntegerGene object InputEncoderUtils { /** Encodes `IntegerGene`, `DoubleGene`, `EnumGene`, and `BooleanGene` of a `RestCallAction` into a vector of `Double` elements */ - fun encode(input: RestCallAction): List { + fun encode(action: RestCallAction): List { - // Create enum encodings + // Encoding enum genes as a mapping string -> int val enumEncoding = mutableMapOf>() - for (parameter in input.parameters.filterIsInstance().sortedBy { it.name }) { - val gene = parameter.primaryGene() + for (parameter in action.parameters.filterIsInstance().sortedBy { it.name }) { + val gene = parameter.gene.getLeafGene() if (gene is EnumGene<*>) { val values = gene.values .map { it.toString() } @@ -29,21 +29,34 @@ object InputEncoderUtils { } } //TODO: We need to handle other types, eg, OptionalGene, and other types of numerics (eg Long and Float) + /** + * The null handling is based on considering null values as -1e6 + */ val encodedFeatures = mutableListOf() - for (gene in input.seeTopGenes()) { + for (gene in action.seeTopGenes()) { + if(gene.getValueAsRawString()==""){ + encodedFeatures.add(-1e6) + continue + } + val gene=gene.getLeafGene() when (gene) { - is IntegerGene -> encodedFeatures.add(gene.value.toDouble()) - is DoubleGene -> encodedFeatures.add(gene.value) - is BooleanGene -> encodedFeatures.add(if (gene.getValueAsRawString().toBoolean()) 1.0 else 0.0) + is IntegerGene -> encodedFeatures.add(gene.value.toDouble() ?: -1e6) + is DoubleGene -> encodedFeatures.add(gene.value ?: -1e6) + is BooleanGene -> { + val raw = gene.getValueAsRawString() + encodedFeatures.add(if (raw != "" && raw.toBoolean()) 1.0 else 0.0 ?: -1e6) + } is EnumGene<*> -> { val paramName = gene.name val rawValue = gene.getValueAsRawString() - val encoded = enumEncoding[paramName]?.get(rawValue) ?: -1 + val encoded = enumEncoding[paramName]?.get(rawValue) ?: -1e6 encodedFeatures.add(encoded.toDouble()) } } } + println(encodedFeatures.joinToString(prefix = "Raw encoded features: [", postfix = "]", separator = ", ")) + // TODO Normalization step should be defined in the config, as normalization may either // weaken or strengthen the classification performance val mean = encodedFeatures.average() @@ -51,10 +64,10 @@ object InputEncoderUtils { return if (stdDev == 0.0) { List(encodedFeatures.size) { 0.0 } + } else { encodedFeatures.map { (it - mean) / stdDev } } - return encodedFeatures } } From 538f062b96ad8a661ba2ec85aa59648f5aefff1c Mon Sep 17 00:00:00 2001 From: Mohsen Taheri Shalmani Date: Mon, 25 Aug 2025 11:36:49 +0200 Subject: [PATCH 2/7] Small update --- .../examples/it/spring/ncs/NCSApplication.kt | 174 +++++++++++++ .../bar/examples/it/spring/ncs/imp/Bessj.java | 119 +++++++++ .../bar/examples/it/spring/ncs/imp/Dto.java | 8 + .../examples/it/spring/ncs/imp/Expint.java | 76 ++++++ .../examples/it/spring/ncs/imp/Fisher.java | 63 +++++ .../bar/examples/it/spring/ncs/imp/Gammq.java | 92 +++++++ .../examples/it/spring/ncs/imp/Remainder.java | 42 +++ .../ncs/imp/TriangleClassification.java | 29 +++ .../examples/it/spring/ncs/NCSController.kt | 6 + .../rest/aiclassification/AIGLMCheck.kt | 4 +- .../core/output/TestSuiteOrganizerTest.kt | 239 ------------------ 11 files changed, 611 insertions(+), 241 deletions(-) create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/NCSApplication.kt create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Bessj.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Dto.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Expint.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Fisher.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Gammq.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Remainder.java create mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/TriangleClassification.java create mode 100644 core-it/src/test/kotlin/bar/examples/it/spring/ncs/NCSController.kt diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/NCSApplication.kt b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/NCSApplication.kt new file mode 100644 index 0000000000..5a35ad9fa7 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/NCSApplication.kt @@ -0,0 +1,174 @@ +package bar.examples.it.spring.ncs + +import bar.examples.it.spring.ncs.imp.Bessj +import bar.examples.it.spring.ncs.imp.Dto +import bar.examples.it.spring.ncs.imp.Expint +import bar.examples.it.spring.ncs.imp.Fisher +import bar.examples.it.spring.ncs.imp.Gammq +import bar.examples.it.spring.ncs.imp.Remainder +import bar.examples.it.spring.ncs.imp.TriangleClassification +import io.swagger.v3.oas.annotations.Parameter +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@SpringBootApplication(exclude = [SecurityAutoConfiguration::class]) +@RestController +@RequestMapping(path = ["/api"]) +open class NCSApplication { + + companion object { + @JvmStatic + fun main(args: Array) { + SpringApplication.run(NCSApplication::class.java, *args) + } + } + + @GetMapping( + value = ["/triangle/{a}/{b}/{c}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun checkTriangle( + @PathVariable("a") + @Parameter(description = "First edge", required = true) + a: Int, + + @PathVariable("b") + @Parameter(description = "Second edge", required = true) + b: Int, + + @PathVariable("c") + @Parameter(description = "Third edge", required = true) + c: Int + ): ResponseEntity { + + val dto = Dto() + dto.resultAsInt = TriangleClassification.classify(a, b, c) + return ResponseEntity.ok(dto) + } + + @GetMapping( + value = ["/bessj/{n}/{x}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun bessj( + @PathVariable("n") + @Parameter(description = "Order n (2 < n ≤ 1000)", required = true) + n: Int, + + @PathVariable("x") + @Parameter(description = "Argument x", required = true) + x: Double + ): ResponseEntity { + if (n <= 2 || n > 1000) { + return ResponseEntity.status(400).build() + } + + val dto = Dto() + val bessj = Bessj() + dto.resultAsDouble = bessj.bessj(n, x) + return ResponseEntity.ok(dto) + } + + @GetMapping( + value = ["/expint/{n}/{x}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun expint( + @PathVariable("n") + @Parameter(description = "Order n", required = true) + n: Int, + + @PathVariable("x") + @Parameter(description = "Argument x", required = true) + x: Double + ): ResponseEntity = + try { + val dto = Dto() + dto.resultAsDouble = Expint.exe(n, x) + ResponseEntity.ok(dto) + } catch (e: RuntimeException) { + ResponseEntity.status(400).build() + } + + @GetMapping( + value = ["/fisher/{m}/{n}/{x}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun fisher( + @PathVariable("m") + @Parameter(description = "Degrees of freedom m (≤ 1000)", required = true) + m: Int, + + @PathVariable("n") + @Parameter(description = "Degrees of freedom n (≤ 1000)", required = true) + n: Int, + + @PathVariable("x") + @Parameter(description = "Argument x", required = true) + x: Double + ): ResponseEntity { + if (m > 1000 || n > 1000) { + return ResponseEntity.status(400).build() + } + + return try { + val dto = Dto() + dto.resultAsDouble = Fisher.exe(m, n, x) + ResponseEntity.ok(dto) + } catch (e: RuntimeException) { + ResponseEntity.status(400).build() + } + } + + @GetMapping( + value = ["/gammq/{a}/{x}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun gammq( + @PathVariable("a") + @Parameter(description = "Shape a", required = true) + a: Double, + + @PathVariable("x") + @Parameter(description = "Argument x", required = true) + x: Double + ): ResponseEntity = + try { + val dto = Dto() + val gammq = Gammq() + dto.resultAsDouble = gammq.exe(a, x) + ResponseEntity.ok(dto) + } catch (e: RuntimeException) { + ResponseEntity.status(400).build() + } + + @GetMapping( + value = ["/remainder/{a}/{b}"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + open fun remainder( + @PathVariable("a") + @Parameter(description = "Dividend a (|a| ≤ 10000)", required = true) + a: Int, + + @PathVariable("b") + @Parameter(description = "Divisor b (|b| ≤ 10000)", required = true) + b: Int + ): ResponseEntity { + val lim = 10_000 + if (a > lim || a < -lim || b > lim || b < -lim) { + return ResponseEntity.status(400).build() + } + + val dto = Dto() + dto.resultAsInt = Remainder.exe(a, b) + return ResponseEntity.ok(dto) + } +} \ No newline at end of file diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Bessj.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Bessj.java new file mode 100644 index 0000000000..cd160c762c --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Bessj.java @@ -0,0 +1,119 @@ +package bar.examples.it.spring.ncs.imp; + +public class Bessj { + + private final double ACC = 40.0; + private final double BIGNO = 1.0e10; + private final double BIGNI = 1.0e-10; + + public double bessj(int n, double x) { + int j, jsum, m; + double ax, bj, bjm, bjp, sum, tox, ans; + + if (n < 2) + throw new IllegalArgumentException("Index n less than 2 in bessj"); + + ax = Math.abs(x); + + if (ax == 0.0) + return 0.0; + else if (ax > n) { + tox = 2.0 / ax; + bjm = bessj0(ax); + bj = bessj1(ax); + + for (j = 1; j < n; j++) { + bjp = j * tox * bj - bjm; + bjm = bj; + bj = bjp; + } + + ans = bj; + } else { + tox = 2.0 / ax; + m = 2 * ((n + (int) Math.round(Math.sqrt(ACC * n))) / 2); + jsum = 0; + bjp = ans = sum = 0.0; + bj = 1.0; + + for (j = m; j > 0; j--) { + bjm = j * tox * bj - bjp; + bjp = bj; + bj = bjm; + + if (Math.abs(bj) > BIGNO) { + bj *= BIGNI; + bjp *= BIGNI; + ans *= BIGNI; + sum *= BIGNI; + } + + if (jsum != 0) + sum += bj; + + jsum = (jsum != 0) ? 0 : 1; + + if (j == n) + ans = bjp; + } + + sum = 2.0 * sum - bj; + ans /= sum; + } + return x < 0.0 && (n & 1) != 0 ? -ans : ans; + } + + + private static double bessj0(double x) { + double ax, z; + double xx, y, ans, ans1, ans2; + + if ((ax = Math.abs(x)) < 8.0) { + y = x * x; + ans1 = 57568490574.0 + y * (-13362590354.0 + y * (651619640.7 + + y * (-11214424.18 + y * (77392.33017 + y * (-184.9052456))))); + ans2 = 57568490411.0 + y * (1029532985.0 + y * (9494680.718 + + y * (59272.64853 + y * (267.8532712 + y * 1.0)))); + ans = ans1 / ans2; + } else { + z = 8.0 / ax; + y = z * z; + xx = ax - 0.785398164; + ans1 = 1.0 + y * (-0.1098628627e-2 + y * (0.2734510407e-4 + + y * (-0.2073370639e-5 + y * 0.2093887211e-6))); + ans2 = -0.1562499995e-1 + y * (0.1430488765e-3 + + y * (-0.6911147651e-5 + y * (0.7621095161e-6 + - y * 0.934935152e-7))); + ans = Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2); + } + return ans; + } + + + private static double bessj1(double x) { + double ax, z; + double xx, y, ans, ans1, ans2; + + if ((ax = Math.abs(x)) < 8.0) { + y = x * x; + ans1 = x * (72362614232.0 + y * (-7895059235.0 + y * (242396853.1 + + y * (-2972611.439 + y * (15704.48260 + y * (-30.16036606)))))); + ans2 = 144725228442.0 + y * (2300535178.0 + y * (18583304.74 + + y * (99447.43394 + y * (376.9991397 + y * 1.0)))); + ans = ans1 / ans2; + } else { + z = 8.0 / ax; + y = z * z; + xx = ax - 2.356194491; + ans1 = 1.0 + y * (0.183105e-2 + y * (-0.3516396496e-4 + + y * (0.2457520174e-5 + y * (-0.240337019e-6)))); + ans2 = 0.04687499995 + y * (-0.2002690873e-3 + + y * (0.8449199096e-5 + y * (-0.88228987e-6 + + y * 0.105787412e-6))); + ans = Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2); + if (x < 0.0) ans = -ans; + } + + return ans; + } +} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Dto.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Dto.java new file mode 100644 index 0000000000..66fe35069c --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Dto.java @@ -0,0 +1,8 @@ +package bar.examples.it.spring.ncs.imp; + +public class Dto { + + public Integer resultAsInt; + + public Double resultAsDouble; +} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Expint.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Expint.java new file mode 100644 index 0000000000..23219c193b --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Expint.java @@ -0,0 +1,76 @@ +package bar.examples.it.spring.ncs.imp; + +public class Expint { + private static final double MAXIT = 100; + private static final double EULER = 0.5772156649; + private static final double FPMIN = 1.0e-30; + private static final double EPS = 1.0e-7; + + public static double exe(int n, double x) { + int i, ii, nm1; + double a, b, c, d, del, fact, h, psi, ans; + + nm1 = n - 1; + + if (n < 0 || x < 0.0 || (x == 0.0 && (n == 0 || n == 1))) + throw new RuntimeException("error: n < 0 or x < 0"); + else { + if (n == 0) + ans = Math.exp(-x) / x; + else { + if (x == 0.0) + ans = 1.0 / nm1; + else { + if (x > 1.0) { + b = x + n; + c = 1.0 / FPMIN; + d = 1.0 / b; + h = d; + + for (i = 1; i <= MAXIT; i++) { + a = -i * (nm1 + i); + b += 2.0; + d = 1.0 / (a * d + b); + c = b + a / c; + del = c * d; + h *= del; + + if (Math.abs(del - 1.0) < EPS) { + return h * Math.exp(-x); + } + } + + throw new RuntimeException("continued fraction failed in expint"); + } else { + ans = (nm1 != 0 ? 1.0 / nm1 : -Math.log(x) - EULER); + fact = 1.0; + + for (i = 1; i <= MAXIT; i++) { + fact *= -x / i; + + if (i != nm1) + del = -fact / (i - nm1); + else { + psi = -EULER; + + for (ii = 1; ii <= nm1; ii++) + psi += 1.0 / ii; + + del = fact * (-Math.log(x) + psi); + } + + ans += del; + + if (Math.abs(del) < Math.abs(ans) * EPS) { + return ans; + } + } + throw new RuntimeException("series failed in expint"); + } + } + } + } + return ans; + } +} + diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Fisher.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Fisher.java new file mode 100644 index 0000000000..38863945ae --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Fisher.java @@ -0,0 +1,63 @@ +package bar.examples.it.spring.ncs.imp; + + + +public class Fisher { + public static double exe(int m, int n, double x) { + int a, b, i, j; + double w, y, z, zk, d, p; + + a = 2 * (m / 2) - m + 2; + b = 2 * (n / 2) - n + 2; + w = (x * m) / n; + z = 1.0 / (1.0 + w); + + if (a == 1) { + if (b == 1) { + p = Math.sqrt(w); + y = 0.3183098862; + d = y * z / p; + p = 2.0 * y * Math.atan(p); + } else { + p = Math.sqrt(w * z); + d = 0.5 * p * z / w; + } + } else if (b == 1) { + p = Math.sqrt(z); + d = 0.5 * z * p; + p = 1.0 - p; + } else { + d = z * z; + p = w * z; + } + + y = 2.0 * w / z; + + if (a == 1) + for (j = b + 2; j <= n; j += 2) { + d *= (1.0 + 1.0 / (j - 2)) * z; + p += d * y / (j - 1); + } + else { + zk = Math.pow(z, (double) ((n - 1) / 2)); + d *= (zk * n) / b; + p = p * zk + w * z * (zk - 1.0) / (z - 1.0); + } + + y = w * z; + z = 2.0 / z; + b = n - 2; + for (i = a + 2; i <= m; i += 2) { + j = i + b; + d *= (y * j) / (i - 2); + p -= z * d / j; + } + + if (p < 0.0) + return 0.0; + else if (p > 1.0) + return 1.0; + else + return p; + } +} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Gammq.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Gammq.java new file mode 100644 index 0000000000..b897cfe9e3 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Gammq.java @@ -0,0 +1,92 @@ +package bar.examples.it.spring.ncs.imp; +public class Gammq { + private static final int ITMAX = 100; + private static final double EPS = 3.0e-7; + private static final double FPMIN = 1.0e-30; + + private double gamser, gammcf, gln; + + private double gammln(double xx) { + + double x,y,tmp,ser; + + double cof[] = {76.18009172947146,-86.50532032941677,24.01409824083091,-1.231739572450155,0.1208650973866179e-2,-0.5395239384953e-5}; + + int j; + + y=x=xx; + tmp=x+5.5; + tmp -= (x+0.5)*Math.log(tmp); + ser=1.000000000190015; + for (j=0;j<=5;j++) ser += cof[j]/++y; + return -tmp+Math.log(2.5066282746310005*ser/x); + } + + private void gcf(double a, double x) + { + int i; + double an,b,c,d,del,h; + + gln=gammln(a); + b=x+1.0-a; + c=1.0/FPMIN; + d=1.0/b; + h=d; + for (i=1;i<=ITMAX;i++) { + an = -i*(i-a); + b += 2.0; + d=an*d+b; + if (Math.abs(d) < FPMIN) d=FPMIN; + c=b+an/c; + if (Math.abs(c) < FPMIN) c=FPMIN; + d=1.0/d; + del=d*c; + h *= del; + if (Math.abs(del-1.0) < EPS) break; + } + if (i > ITMAX) throw new RuntimeException ("a too large, ITMAX too small in gcf"); + gammcf=Math.exp(-x+a*Math.log(x)-gln)*h; + } + + private void gser(double a, double x) { + + int n; + double sum,del,ap; + + gln=gammln(a); + + if (x <= 0.0) { + if (x < 0.0) throw new RuntimeException ("x less than 0 in routine gser"); + gamser=0.0; + return; + } + else { + ap=a; + del=sum=1.0/a; + for (n=1;n<=ITMAX;n++) { + ++ap; + del *= x/ap; + sum += del; + if (Math.abs(del) < Math.abs(sum)*EPS) { + gamser=sum*Math.exp(-x+a*Math.log(x)-gln); + return; + } + } + throw new RuntimeException ("a too large, ITMAX too small in routine gser"); + } + } + + public double exe(double a, double x) { + if (x < 0.0 || a <= 0.0) throw new RuntimeException("Invalid arguments in routine gammq"); + if (x < (a+1.0)) { + gser(a,x); + return 1-gamser; + } + else { + gcf(a,x); + return gammcf; + } + } + +} + diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Remainder.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Remainder.java new file mode 100644 index 0000000000..f5f565bf54 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Remainder.java @@ -0,0 +1,42 @@ +package bar.examples.it.spring.ncs.imp; + +public class Remainder { + public static int exe(int a, int b) { + int r = 0 - 1; + int cy = 0; + int ny = 0; + + if (a == 0) ; + else if (b == 0) ; + else if (a > 0) + if (b > 0) + while ((a - ny) >= b) { + ny = ny + b; + r = a - ny; + cy = cy + 1; + } + else // b<0 + //while((a+ny)>=Math.abs(b)) + while ((a + ny) >= ((b >= 0) ? b : -b)) { + ny = ny + b; + r = a + ny; + cy = cy - 1; + } + else // a<0 + if (b > 0) + //while(Math.abs(a+ny)>=b) + while (((a + ny) >= 0 ? (a + ny) : -(a + ny)) >= b) { + ny = ny + b; + r = a + ny; + cy = cy - 1; + } + else + while (b >= (a - ny)) { + ny = ny + b; + //r=Math.abs(a-ny); + r = ((a - ny) >= 0 ? (a - ny) : -(a - ny)); + cy = cy + 1; + } + return r; + } +} \ No newline at end of file diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/TriangleClassification.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/TriangleClassification.java new file mode 100644 index 0000000000..22adc0d1d5 --- /dev/null +++ b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/TriangleClassification.java @@ -0,0 +1,29 @@ +package bar.examples.it.spring.ncs.imp; + +public class TriangleClassification { + + public static int classify(int a, int b, int c) { + + if (a <= 0 || b <= 0 || c <= 0) { + return 0; + } + + if (a == b && b == c) { + return 3; + } + + int max = Math.max(a, Math.max(b, c)); + + if ((max == a && max - b - c >= 0) || + (max == b && max - a - c >= 0) || + (max == c && max - a - b >= 0)) { + return 0; + } + + if (a == b || b == c || a == c) { + return 2; + } else { + return 1; + } + } +} diff --git a/core-it/src/test/kotlin/bar/examples/it/spring/ncs/NCSController.kt b/core-it/src/test/kotlin/bar/examples/it/spring/ncs/NCSController.kt new file mode 100644 index 0000000000..0e4edd3296 --- /dev/null +++ b/core-it/src/test/kotlin/bar/examples/it/spring/ncs/NCSController.kt @@ -0,0 +1,6 @@ +package bar.examples.it.spring.ncs + +import bar.examples.it.spring.SpringController + +class NCSController : SpringController(NCSApplication::class.java) + diff --git a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt index aee0b6f83b..16450fbbac 100644 --- a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt +++ b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt @@ -31,8 +31,8 @@ class AIGLMCheck : IntegrationTestRestBase() { companion object { @JvmStatic fun init() { -// initClass(NCSController()) - initClass(BasicController()) + initClass(NCSController()) +// initClass(BasicController()) // initClass(MultiTypeController()) } diff --git a/core/src/test/kotlin/org/evomaster/core/output/TestSuiteOrganizerTest.kt b/core/src/test/kotlin/org/evomaster/core/output/TestSuiteOrganizerTest.kt index 298c5570dd..e69de29bb2 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/TestSuiteOrganizerTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/TestSuiteOrganizerTest.kt @@ -1,239 +0,0 @@ -package org.evomaster.core.output - -import org.evomaster.core.TestUtils -import org.evomaster.core.output.naming.NumberedTestCaseNamingStrategy -import org.evomaster.core.output.naming.RestActionTestCaseUtils.getEvaluatedIndividualWith -import org.evomaster.core.output.naming.RestActionTestCaseUtils.getRestCallAction -import org.evomaster.core.output.sorting.SortingStrategy -import org.evomaster.core.problem.api.param.Param -import org.evomaster.core.problem.enterprise.EnterpriseActionGroup -import org.evomaster.core.problem.enterprise.SampleType -import org.evomaster.core.problem.graphql.GQMethodType -import org.evomaster.core.problem.graphql.GraphQLAction -import org.evomaster.core.problem.graphql.GraphQLIndividual -import org.evomaster.core.problem.graphql.GraphQlCallResult -import org.evomaster.core.problem.graphql.param.GQInputParam -import org.evomaster.core.problem.rest.data.HttpVerb -import org.evomaster.core.problem.rpc.RPCCallAction -import org.evomaster.core.problem.rpc.RPCIndividual -import org.evomaster.core.problem.rpc.param.RPCParam -import org.evomaster.core.search.EvaluatedIndividual -import org.evomaster.core.search.FitnessValue -import org.evomaster.core.search.Solution -import org.evomaster.core.search.gene.wrapper.OptionalGene -import org.evomaster.core.search.gene.string.StringGene -import org.junit.Test -import org.junit.jupiter.api.Assertions.assertEquals -import java.util.UUID - -class TestSuiteOrganizerTest { - - companion object { - val sortingStrategy = SortingStrategy.TARGET_INCREMENTAL - } - - @Test - fun restSortedByPathSegmentFirst() { - val noPathSegmentInd = getEvaluatedIndividualWith(getRestCallAction("/")) - val onePathSegmentInd = getEvaluatedIndividualWith(getRestCallAction("/organization")) - val twoPathSegmentsInd = getEvaluatedIndividualWith(getRestCallAction("/organization/{name}")) - val individuals = mutableListOf(noPathSegmentInd, onePathSegmentInd, twoPathSegmentsInd) - individuals.shuffle() - val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - - val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) - - assertEquals(sortedTestCases[0].test, noPathSegmentInd) - assertEquals(sortedTestCases[1].test, onePathSegmentInd) - assertEquals(sortedTestCases[2].test, twoPathSegmentsInd) - } - - @Test - fun restSortedByStatusCodeWhenEqualPathSegmentSize() { - val status200Ind = getEvaluatedIndividualWith(getRestCallAction("/organization"), 200) - val status401Ind = getEvaluatedIndividualWith(getRestCallAction("/organization"), 401) - val status500Ind = getEvaluatedIndividualWith(getRestCallAction("/organization"), 500) - val individuals = mutableListOf(status200Ind, status401Ind, status500Ind) - individuals.shuffle() - val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - - val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) - - assertEquals(sortedTestCases[0].test, status500Ind) - assertEquals(sortedTestCases[1].test, status200Ind) - assertEquals(sortedTestCases[2].test, status401Ind) - } - - @Test - fun restSortedByMethodWhenEqualPathSegmentsAndStatusCode() { - val getInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.GET)) - val postInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.POST)) - val putInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.PUT)) - val deleteInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.DELETE)) - val optionsInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.OPTIONS)) - val patchInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.PATCH)) - val traceInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.TRACE)) - val headInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.HEAD)) - val individuals = mutableListOf(getInd, postInd, putInd, deleteInd, optionsInd, patchInd, traceInd, headInd) - individuals.shuffle() - val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - - val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) - - assertEquals(sortedTestCases[0].test, getInd) - assertEquals(sortedTestCases[1].test, postInd) - assertEquals(sortedTestCases[2].test, putInd) - assertEquals(sortedTestCases[3].test, deleteInd) - assertEquals(sortedTestCases[4].test, optionsInd) - assertEquals(sortedTestCases[5].test, patchInd) - assertEquals(sortedTestCases[6].test, traceInd) - assertEquals(sortedTestCases[7].test, headInd) - } - - @Test - fun graphSortedByMethodNameFirst() { - val aLetterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "aLetterMethod") - val bLetterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "bLetterMethod") - val cLetterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "cLetterMethod") - val individuals = mutableListOf(aLetterIndividual, bLetterIndividual, cLetterIndividual) - individuals.shuffle() - val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - - val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) - - assertEquals(sortedTestCases[0].test, aLetterIndividual) - assertEquals(sortedTestCases[1].test, bLetterIndividual) - assertEquals(sortedTestCases[2].test, cLetterIndividual) - } - - @Test - fun graphSortedByMethodTypeWhenEqualMethodNameAndParametersSize() { - val paramLambda = { name: String, value: String -> getGraphQLParam(name, value) } - val queryOneParameterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(1, paramLambda)) - val queryTwoParametersIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(2, paramLambda)) - val mutationOneParameterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.MUTATION, "myMethod", getListOfParams(1, paramLambda)) - val mutationTwoParametersIndividual = getGraphQLEvaluatedIndividual(GQMethodType.MUTATION, "myMethod", getListOfParams(2, paramLambda)) - val individuals = mutableListOf(queryOneParameterIndividual, queryTwoParametersIndividual, mutationOneParameterIndividual, mutationTwoParametersIndividual) - individuals.shuffle() - val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - - val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) - - assertEquals(sortedTestCases[0].test, queryOneParameterIndividual) - assertEquals(sortedTestCases[1].test, queryTwoParametersIndividual) - assertEquals(sortedTestCases[2].test, mutationOneParameterIndividual) - assertEquals(sortedTestCases[3].test, mutationTwoParametersIndividual) - } - - @Test - fun graphSortedByAmountOfParametersWhenEqualMethodNameAndType() { - val paramLambda = { name: String, value: String -> getGraphQLParam(name, value) } - val oneParameterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(1, paramLambda)) - val twoParametersIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(2, paramLambda)) - val threeParametersIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(3, paramLambda)) - val individuals = mutableListOf(oneParameterIndividual, twoParametersIndividual, threeParametersIndividual) - individuals.shuffle() - val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - - val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) - - assertEquals(sortedTestCases[0].test, oneParameterIndividual) - assertEquals(sortedTestCases[1].test, twoParametersIndividual) - assertEquals(sortedTestCases[2].test, threeParametersIndividual) - } - - @Test - fun rpcSortedByClassNameFirst() { - val aFakeClassIndividual = getRPCEvaluatedIndividual("aFakeInterfaceClass:fakeInterfaceMethod") - val bFakeClassIndividual = getRPCEvaluatedIndividual("bFakeInterfaceClass:fakeInterfaceMethod") - val cFakeClassIndividual = getRPCEvaluatedIndividual("cFakeInterfaceClass:fakeInterfaceMethod") - val individuals = mutableListOf(aFakeClassIndividual, bFakeClassIndividual, cFakeClassIndividual) - individuals.shuffle() - val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - - val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) - - assertEquals(sortedTestCases[0].test, aFakeClassIndividual) - assertEquals(sortedTestCases[1].test, bFakeClassIndividual) - assertEquals(sortedTestCases[2].test, cFakeClassIndividual) - } - - @Test - fun rpcSortedByMethodNameWhenEqualClassName() { - val aFakeMethodIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:aFakeInterfaceMethod") - val bFakeMethodIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:bFakeInterfaceMethod") - val cFakeMethodIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:cFakeInterfaceMethod") - val individuals = mutableListOf(aFakeMethodIndividual, bFakeMethodIndividual, cFakeMethodIndividual) - individuals.shuffle() - val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - - val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) - - assertEquals(sortedTestCases[0].test, aFakeMethodIndividual) - assertEquals(sortedTestCases[1].test, bFakeMethodIndividual) - assertEquals(sortedTestCases[2].test, cFakeMethodIndividual) - } - - @Test - fun rpcSortedByAmountOfParametersWhenClassAndMethodNames() { - val paramLambda = { name: String, value: String -> getRPCParam(name, value) } - val oneParameterIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:fakeInterfaceMethod", getListOfParams(1, paramLambda)) - val twoParametersIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:fakeInterfaceMethod", getListOfParams(2, paramLambda)) - val threeParametersIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:fakeInterfaceMethod", getListOfParams(3, paramLambda)) - val individuals = mutableListOf(oneParameterIndividual, twoParametersIndividual, threeParametersIndividual) - individuals.shuffle() - val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - - val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) - - assertEquals(sortedTestCases[0].test, oneParameterIndividual) - assertEquals(sortedTestCases[1].test, twoParametersIndividual) - assertEquals(sortedTestCases[2].test, threeParametersIndividual) - } - - private fun getGraphQLEvaluatedIndividual(query: GQMethodType, methodName: String, params: MutableList = mutableListOf()): EvaluatedIndividual { - val action = GraphQLAction(methodName, methodName, query, params) - - val actions = mutableListOf>() - actions.add(EnterpriseActionGroup(mutableListOf(action), GraphQLAction::class.java)) - - val individual = GraphQLIndividual(SampleType.RANDOM, actions) - TestUtils.doInitializeIndividualForTesting(individual) - - val results = listOf(GraphQlCallResult(action.getLocalId())) - return EvaluatedIndividual(FitnessValue(0.0), individual, results) - } - - private fun getListOfParams(amount: Int, paramFunction: (name: String, value: String) -> Param): MutableList { - val params = mutableListOf() - for (i in 0..amount) { - val name = UUID.randomUUID().toString() - val value = UUID.randomUUID().toString() - params.add(paramFunction(name, value)) - } - return params - } - - private fun getGraphQLParam(name: String, value: String): GQInputParam { - val op = OptionalGene(name, StringGene(name, value)) - return GQInputParam(name, op) - } - - private fun getRPCEvaluatedIndividual(interfaceId: String, params: MutableList = mutableListOf()): EvaluatedIndividual { - val action = RPCCallAction(interfaceId, "${interfaceId}_0", params, null, null) - val externalAction = EvaluatedIndividualBuilder.buildFakeDbExternalServiceAction(1).plus(EvaluatedIndividualBuilder.buildFakeRPCExternalServiceAction(1)) - - val individual = RPCIndividual(SampleType.RANDOM, actions=mutableListOf(action), externalServicesActions = mutableListOf(externalAction)) - TestUtils.doInitializeIndividualForTesting(individual) - - val results = listOf(GraphQlCallResult(action.getLocalId())) - return EvaluatedIndividual(FitnessValue(0.0), individual, results) - } - - private fun getRPCParam(name: String, value: String): RPCParam { - val op = OptionalGene(name, StringGene(name, value)) - return RPCParam(name, op) - } - - -} From 8b4491026dede5b0ec3a1952386aab3a3ac66d8f Mon Sep 17 00:00:00 2001 From: Mohsen Taheri Shalmani Date: Mon, 25 Aug 2025 13:52:27 +0200 Subject: [PATCH 3/7] Updating encoder and AI models to handell null values Encoder is updated to handle null values The models are applied on three SUT 1. NCS API from EMB examples 2. Basic API 3. Multitype API --- .../rest/aiclassification/AIGLMCheck.kt | 30 +++++--------- .../rest/aiclassification/AIGaussianCheck.kt | 31 +++++--------- .../classifier/GaussianOnlineClassifier.kt | 30 ++++++++++++-- .../rest/classifier/GeneralizedLinearModel.kt | 30 ++++++++++++-- .../rest/classifier/InputEncoderUtils.kt | 40 +++++++++++-------- 5 files changed, 96 insertions(+), 65 deletions(-) diff --git a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt index 16450fbbac..216b5923c9 100644 --- a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt +++ b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt @@ -15,6 +15,7 @@ import org.evomaster.core.problem.rest.builder.RestActionBuilderV3 import org.evomaster.core.problem.rest.schema.RestSchema import org.evomaster.core.EMConfig import org.evomaster.core.problem.rest.classifier.GLMOnlineClassifier +import org.evomaster.core.problem.rest.classifier.InputEncoderUtils import org.evomaster.core.problem.rest.schema.OpenApiAccess import org.evomaster.core.problem.rest.service.sampler.AbstractRestSampler import org.evomaster.core.search.action.Action @@ -100,9 +101,6 @@ class AIGLMCheck : IntegrationTestRestBase() { val actionList = actionCluster.values.filterIsInstance() val endpointToDimension = mutableMapOf() - val endpointToCorrectPrediction = mutableMapOf() - val endpointToTotalExecution = mutableMapOf() - val endpointToAccuracy = mutableMapOf() for (action in actionList) { val name = action.getName() @@ -123,9 +121,6 @@ class AIGLMCheck : IntegrationTestRestBase() { println("Endpoint: $name, dimension: $dimension") endpointToDimension[name] = dimension - endpointToCorrectPrediction[name] = 0 - endpointToTotalExecution[name] = 0 - endpointToAccuracy[name] = 0.0 } /** @@ -161,9 +156,6 @@ class AIGLMCheck : IntegrationTestRestBase() { val classifier = endpointToClassifier[name] val dimension = endpointToDimension[name] val geneValues = sampledAction.parameters.map { it.gene.getValueAsRawString() } - var cp = endpointToCorrectPrediction[name]!! - var tot = endpointToTotalExecution[name]!! - var ac = endpointToAccuracy[name]!! println("*************************************************") println("Path : $name") @@ -171,7 +163,7 @@ class AIGLMCheck : IntegrationTestRestBase() { println("Dimension : $dimension") println("Input Genes : ${geneValues.joinToString(", ")}") println("Genes Size : ${geneValues.size}") - println("cp, tot, ac : $cp, $tot, $ac") + println("cp, tot, ac : ${classifier?.getCorrectPredictions()}, ${classifier?.getTotalRequests()}, ${classifier?.getAccuracy()}") // executeRestCallAction is replaced with createIndividual to avoid override error // val individual = createIndividual(listOf(sampledAction), SampleType.RANDOM) @@ -186,18 +178,19 @@ class AIGLMCheck : IntegrationTestRestBase() { } // Warmup cold classifiers by at least n request val n = 2 - val isCold = tot <= n + val isCold = classifier.getTotalRequests() <= n if (isCold) { println("Warmup by at least $n request") val result = executeRestCallAction(action, "$baseUrlOfSut") classifier.updateModel(action, result) - tot += 1 - endpointToTotalExecution[name] = tot + classifier.setTot(classifier.getTotalRequests() + 1) continue } // Classification println("Classifying!") + val rawEncodedFeatures = InputEncoderUtils.encode(sampledAction).rawEncodedFeatures + println("Raw encoded features are : ${rawEncodedFeatures.joinToString(", ")}") val classification = classifier.classify(action) val p200 = classification.probabilities[200]!! val p400 = classification.probabilities[400]!! @@ -214,7 +207,7 @@ class AIGLMCheck : IntegrationTestRestBase() { if (prediction != 400) { sendOrNot = true }else{ - sendOrNot = if(Math.random() > ac) true else false + sendOrNot = if(Math.random() > classifier.getAccuracy()) true else false } // Execute the request and update @@ -223,14 +216,9 @@ class AIGLMCheck : IntegrationTestRestBase() { println("Response : ${result.getStatusCode()}") if (result.getStatusCode()==prediction) { - cp = cp + 1 + classifier.setCp(classifier.getCorrectPredictions() + 1) } - tot = tot + 1 - ac = cp.toDouble() / tot - - endpointToCorrectPrediction[name] = cp - endpointToTotalExecution[name] = tot - endpointToAccuracy[name] = ac + classifier.setTot(classifier.getTotalRequests() + 1) println("Updating the classifier!") classifier.updateModel(action, result) diff --git a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt index e4996ef0ac..cab0da7890 100644 --- a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt +++ b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt @@ -15,6 +15,7 @@ import org.evomaster.core.problem.rest.builder.RestActionBuilderV3 import org.evomaster.core.problem.rest.schema.RestSchema import org.evomaster.core.EMConfig import org.evomaster.core.problem.rest.classifier.GaussianOnlineClassifier +import org.evomaster.core.problem.rest.classifier.InputEncoderUtils import org.evomaster.core.problem.rest.schema.OpenApiAccess import org.evomaster.core.problem.rest.service.sampler.AbstractRestSampler import org.evomaster.core.search.action.Action @@ -95,9 +96,6 @@ class AIGaussianCheck : IntegrationTestRestBase() { val actionList = actionCluster.values.filterIsInstance() val endpointToDimension = mutableMapOf() - val endpointToCorrectPrediction = mutableMapOf() - val endpointToTotalExecution = mutableMapOf() - val endpointToAccuracy = mutableMapOf() for (action in actionList) { val name = action.getName() @@ -118,10 +116,6 @@ class AIGaussianCheck : IntegrationTestRestBase() { println("Endpoint: $name, dimension: $dimension") endpointToDimension[name] = dimension - - endpointToCorrectPrediction[name] = 0 - endpointToTotalExecution[name] = 0 - endpointToAccuracy[name] = 0.0 } /** @@ -157,9 +151,6 @@ class AIGaussianCheck : IntegrationTestRestBase() { val classifier = endpointToClassifier[name] val dimension = endpointToDimension[name] val geneValues = sampledAction.parameters.map { it.gene.getValueAsRawString()} - var cp = endpointToCorrectPrediction[name]!! - var tot = endpointToTotalExecution[name]!! - var ac = endpointToAccuracy[name]!! println("*************************************************") println("Path : $name") @@ -167,7 +158,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { println("Dimension : $dimension") println("Input Genes : ${geneValues.joinToString(", ")}") println("Genes Size : ${geneValues.size}") - println("cp, tot, ac : $cp, $tot, $ac") + println("cp, tot, ac : ${classifier?.getCorrectPredictions()}, ${classifier?.getTotalRequests()}, ${classifier?.getAccuracy()}") // executeRestCallAction is replaced with createIndividual to avoid override error // val individual = createIndividual(listOf(sampledAction), SampleType.RANDOM) @@ -182,19 +173,20 @@ class AIGaussianCheck : IntegrationTestRestBase() { } // Warmup cold classifiers by at least n request val n = 2 - val isCold = tot <= n + val isCold = classifier.getTotalRequests() <= n if (isCold) { println("Warmup by at least $n request") val result = executeRestCallAction(action, "$baseUrlOfSut") println("Response : ${result.getStatusCode()}") classifier.updateModel(action, result) - tot += 1 - endpointToTotalExecution[name] = tot + classifier.setTot(classifier.getTotalRequests() + 1) continue } // Classification println("Classifying!") + val rawEncodedFeatures = InputEncoderUtils.encode(sampledAction).rawEncodedFeatures + println("Raw encoded features are : ${rawEncodedFeatures.joinToString(", ")}") val classification = classifier.classify(action) val p200 = classification.probabilities[200]!! val p400 = classification.probabilities[400]!! @@ -211,7 +203,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { if (prediction != 400) { sendOrNot = true }else{ - sendOrNot = if(Math.random() > ac) true else false + sendOrNot = if(Math.random() > classifier.getAccuracy()) true else false } // Execute the request and update @@ -220,14 +212,9 @@ class AIGaussianCheck : IntegrationTestRestBase() { println("Response : ${result.getStatusCode()}") if (result.getStatusCode()==prediction) { - cp = cp + 1 + classifier.setCp(classifier.getCorrectPredictions() + 1) } - tot = tot + 1 - ac = cp.toDouble() / tot - - endpointToCorrectPrediction[name] = cp - endpointToTotalExecution[name] = tot - endpointToAccuracy[name] = ac + classifier.setTot(classifier.getTotalRequests() + 1) println("Updating the classifier!") classifier.updateModel(action, result) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt index 785f70987a..3b7ea63889 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt @@ -36,11 +36,19 @@ class GaussianOnlineClassifier : AIModel { private var density200: Density? = null private var density400: Density? = null + // classifier state + private var cp: Int = 0 // correct predictions + private var tot: Int = 1 // total requests + private var ac: Double = 0.0 // accuracy ratio + fun setDimension(d: Int) { require(d > 0) { "Dimension must be positive." } this.dimension = d this.density200 = Density(d) this.density400 = Density(d) + this.cp = 0 + this.tot = 1 + this.ac = 0.0 } fun getDimension(): Int { @@ -48,6 +56,17 @@ class GaussianOnlineClassifier : AIModel { return this.dimension!! } + fun setCp(cp: Int) { + this.cp = cp + } + fun setTot(tot: Int){ + this.tot = tot + } + + fun getCorrectPredictions(): Int = cp + fun getTotalRequests(): Int = tot + fun getAccuracy(): Double = if (tot == 0) 0.0 else cp.toDouble() / tot + fun getDensity200(): Density { check(this.density200 != null) { "Classifier not initialized. Call setDimension first." } return this.density200!! @@ -59,7 +78,7 @@ class GaussianOnlineClassifier : AIModel { } override fun updateModel(input: RestCallAction, output: RestCallResult) { - val inputVector = InputEncoderUtils.encode(input) + val inputVector = InputEncoderUtils.encode(input).normalizedEncodedFeatures if (inputVector.size != this.dimension) { throw IllegalArgumentException("Expected input vector of size ${this.dimension} but got ${inputVector.size}") @@ -73,7 +92,7 @@ class GaussianOnlineClassifier : AIModel { } override fun classify(input: RestCallAction): AIResponseClassification { - val inputVector = InputEncoderUtils.encode(input) + val inputVector = InputEncoderUtils.encode(input).normalizedEncodedFeatures if (inputVector.size != this.dimension) { throw IllegalArgumentException("Expected input vector of size ${this.dimension} but got ${inputVector.size}") @@ -100,7 +119,12 @@ class GaussianOnlineClassifier : AIModel { } override fun estimateAccuracy(endpoint: Endpoint): Double { - TODO("Not yet implemented") + // Strict accuracy + //TODO this accuracy can be dynamic for example based on the last 100 requests + if (this.tot == 0) { + return 0.0 + } + return this.cp.toDouble() / this.tot } private fun logLikelihood(x: List, stats: Density): Double { diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt index d637b3a34e..2baa3e9e48 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt @@ -26,12 +26,20 @@ class GLMOnlineClassifier( private var weights: MutableList? = null private var bias: Double = 0.0 + // classifier state + private var cp: Int = 0 // correct predictions + private var tot: Int = 1 // total requests + private var ac: Double = 0.0 // accuracy ratio + /** Must be called once to initialize model weights based on dimension */ fun setDimension(d: Int) { require(d > 0) { "Dimension must be positive." } dimension = d weights = MutableList(d) { 0.0 } bias = 0.0 + this.cp = 0 + this.tot = 0 + this.ac = 0.0 } fun getModelParams(): List { @@ -44,8 +52,19 @@ class GLMOnlineClassifier( return this.dimension!! } + fun setCp(cp: Int) { + this.cp = cp + } + fun setTot(tot: Int){ + this.tot = tot + } + + fun getCorrectPredictions(): Int = cp + fun getTotalRequests(): Int = tot + fun getAccuracy(): Double = if (tot == 0) 0.0 else cp.toDouble() / tot + override fun classify(input: RestCallAction): AIResponseClassification { - val x = InputEncoderUtils.encode(input) + val x = InputEncoderUtils.encode(input).normalizedEncodedFeatures val dim = dimension ?: throw IllegalStateException("Dimension not set. Call setDimension() first.") if (x.size != dim) throw IllegalArgumentException("Expected input vector of size $dim but got ${x.size}") @@ -63,11 +82,16 @@ class GLMOnlineClassifier( } override fun estimateAccuracy(endpoint: Endpoint): Double { - TODO("Not yet implemented") + // Strict accuracy + //TODO this accuracy can be dynamic for example based on the last 100 requests + if (this.tot == 0) { + return 0.0 + } + return this.cp.toDouble() / this.tot } override fun updateModel(input: RestCallAction, output: RestCallResult) { - val x = InputEncoderUtils.encode(input) + val x = InputEncoderUtils.encode(input).normalizedEncodedFeatures val dim = dimension ?: throw IllegalStateException("Dimension not set. Call setDimension() first.") if (x.size != dim) throw IllegalArgumentException("Expected input vector of size $dim but got ${x.size}") diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/InputEncoderUtils.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/InputEncoderUtils.kt index 42dfc169cc..804f7f648e 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/InputEncoderUtils.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/InputEncoderUtils.kt @@ -14,8 +14,13 @@ import org.evomaster.core.search.gene.numeric.IntegerGene */ object InputEncoderUtils { + data class EncodedFeatures( + val rawEncodedFeatures: List, + val normalizedEncodedFeatures: List + ) + /** Encodes `IntegerGene`, `DoubleGene`, `EnumGene`, and `BooleanGene` of a `RestCallAction` into a vector of `Double` elements */ - fun encode(action: RestCallAction): List { + fun encode(action: RestCallAction): EncodedFeatures { // Encoding enum genes as a mapping string -> int val enumEncoding = mutableMapOf>() @@ -32,42 +37,45 @@ object InputEncoderUtils { /** * The null handling is based on considering null values as -1e6 */ - val encodedFeatures = mutableListOf() + val rawEncodedFeatures = mutableListOf() for (gene in action.seeTopGenes()) { if(gene.getValueAsRawString()==""){ - encodedFeatures.add(-1e6) + rawEncodedFeatures.add(-1e6) continue } val gene=gene.getLeafGene() when (gene) { - is IntegerGene -> encodedFeatures.add(gene.value.toDouble() ?: -1e6) - is DoubleGene -> encodedFeatures.add(gene.value ?: -1e6) + is IntegerGene -> rawEncodedFeatures.add(gene.value.toDouble() ?: -1e6) + is DoubleGene -> rawEncodedFeatures.add(gene.value ?: -1e6) is BooleanGene -> { val raw = gene.getValueAsRawString() - encodedFeatures.add(if (raw != "" && raw.toBoolean()) 1.0 else 0.0 ?: -1e6) + rawEncodedFeatures.add(if (raw != "" && raw.toBoolean()) 1.0 else 0.0 ?: -1e6) } is EnumGene<*> -> { val paramName = gene.name val rawValue = gene.getValueAsRawString() val encoded = enumEncoding[paramName]?.get(rawValue) ?: -1e6 - encodedFeatures.add(encoded.toDouble()) + rawEncodedFeatures.add(encoded.toDouble()) } } } - println(encodedFeatures.joinToString(prefix = "Raw encoded features: [", postfix = "]", separator = ", ")) - // TODO Normalization step should be defined in the config, as normalization may either // weaken or strengthen the classification performance - val mean = encodedFeatures.average() - val stdDev = kotlin.math.sqrt(encodedFeatures.map { (it - mean) * (it - mean) }.average()) + val mean = rawEncodedFeatures.average() + val stdDev = kotlin.math.sqrt(rawEncodedFeatures.map { (it - mean) * (it - mean) }.average()) - return if (stdDev == 0.0) { - List(encodedFeatures.size) { 0.0 } + val normalizedEncodedFeatures: List = + if (stdDev == 0.0) { + List(rawEncodedFeatures.size) { 0.0 } + } else { + rawEncodedFeatures.map { (it - mean) / stdDev } + } - } else { - encodedFeatures.map { (it - mean) / stdDev } - } + return EncodedFeatures( + rawEncodedFeatures = rawEncodedFeatures, + normalizedEncodedFeatures = normalizedEncodedFeatures + ) } } From 333a8c8f65e5ab91b43be5e6e0ed00b36a0de0ab Mon Sep 17 00:00:00 2001 From: Mohsen Taheri Shalmani Date: Tue, 26 Aug 2025 10:00:28 +0200 Subject: [PATCH 4/7] Update encoder The encoder has been updated to handle null values. The models are applied to the SUTs Basic API Multitype API --- .../aiclassification/ncs/NCSApplication.kt | 174 ------------------ .../aiclassification/ncs/imp/Bessj.java | 119 ------------ .../spring/aiclassification/ncs/imp/Dto.java | 8 - .../aiclassification/ncs/imp/Expint.java | 76 -------- .../aiclassification/ncs/imp/Fisher.java | 63 ------- .../aiclassification/ncs/imp/Gammq.java | 92 --------- .../aiclassification/ncs/imp/Remainder.java | 42 ----- .../ncs/imp/TriangleClassification.java | 29 --- .../examples/it/spring/ncs/NCSApplication.kt | 174 ------------------ .../bar/examples/it/spring/ncs/imp/Bessj.java | 119 ------------ .../bar/examples/it/spring/ncs/imp/Dto.java | 8 - .../examples/it/spring/ncs/imp/Expint.java | 76 -------- .../examples/it/spring/ncs/imp/Fisher.java | 63 ------- .../bar/examples/it/spring/ncs/imp/Gammq.java | 92 --------- .../examples/it/spring/ncs/imp/Remainder.java | 42 ----- .../ncs/imp/TriangleClassification.java | 29 --- .../aiclassification/ncs/NCSController.kt | 6 - .../examples/it/spring/ncs/NCSController.kt | 6 - .../rest/aiclassification/AIGLMCheck.kt | 6 +- .../rest/aiclassification/AIGaussianCheck.kt | 6 +- 20 files changed, 4 insertions(+), 1226 deletions(-) delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSApplication.kt delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Bessj.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Dto.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Expint.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Fisher.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Gammq.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Remainder.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/TriangleClassification.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/NCSApplication.kt delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Bessj.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Dto.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Expint.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Fisher.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Gammq.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Remainder.java delete mode 100644 core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/TriangleClassification.java delete mode 100644 core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSController.kt delete mode 100644 core-it/src/test/kotlin/bar/examples/it/spring/ncs/NCSController.kt diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSApplication.kt b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSApplication.kt deleted file mode 100644 index e0d9957117..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSApplication.kt +++ /dev/null @@ -1,174 +0,0 @@ -package bar.examples.it.spring.aiclassification.ncs - -import bar.examples.it.spring.aiclassification.ncs.imp.Bessj -import bar.examples.it.spring.aiclassification.ncs.imp.Dto -import bar.examples.it.spring.aiclassification.ncs.imp.Expint -import bar.examples.it.spring.aiclassification.ncs.imp.Fisher -import bar.examples.it.spring.aiclassification.ncs.imp.Gammq -import bar.examples.it.spring.aiclassification.ncs.imp.Remainder -import bar.examples.it.spring.aiclassification.ncs.imp.TriangleClassification -import io.swagger.v3.oas.annotations.Parameter -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration -import org.springframework.http.MediaType -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController - -@SpringBootApplication(exclude = [SecurityAutoConfiguration::class]) -@RestController -@RequestMapping(path = ["/api"]) -open class NCSApplication { - - companion object { - @JvmStatic - fun main(args: Array) { - SpringApplication.run(NCSApplication::class.java, *args) - } - } - - @GetMapping( - value = ["/triangle/{a}/{b}/{c}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun checkTriangle( - @PathVariable("a") - @Parameter(description = "First edge", required = true) - a: Int, - - @PathVariable("b") - @Parameter(description = "Second edge", required = true) - b: Int, - - @PathVariable("c") - @Parameter(description = "Third edge", required = true) - c: Int - ): ResponseEntity { - - val dto = Dto() - dto.resultAsInt = TriangleClassification.classify(a, b, c) - return ResponseEntity.ok(dto) - } - - @GetMapping( - value = ["/bessj/{n}/{x}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun bessj( - @PathVariable("n") - @Parameter(description = "Order n (2 < n ≤ 1000)", required = true) - n: Int, - - @PathVariable("x") - @Parameter(description = "Argument x", required = true) - x: Double - ): ResponseEntity { - if (n <= 2 || n > 1000) { - return ResponseEntity.status(400).build() - } - - val dto = Dto() - val bessj = Bessj() - dto.resultAsDouble = bessj.bessj(n, x) - return ResponseEntity.ok(dto) - } - - @GetMapping( - value = ["/expint/{n}/{x}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun expint( - @PathVariable("n") - @Parameter(description = "Order n", required = true) - n: Int, - - @PathVariable("x") - @Parameter(description = "Argument x", required = true) - x: Double - ): ResponseEntity = - try { - val dto = Dto() - dto.resultAsDouble = Expint.exe(n, x) - ResponseEntity.ok(dto) - } catch (e: RuntimeException) { - ResponseEntity.status(400).build() - } - - @GetMapping( - value = ["/fisher/{m}/{n}/{x}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun fisher( - @PathVariable("m") - @Parameter(description = "Degrees of freedom m (≤ 1000)", required = true) - m: Int, - - @PathVariable("n") - @Parameter(description = "Degrees of freedom n (≤ 1000)", required = true) - n: Int, - - @PathVariable("x") - @Parameter(description = "Argument x", required = true) - x: Double - ): ResponseEntity { - if (m > 1000 || n > 1000) { - return ResponseEntity.status(400).build() - } - - return try { - val dto = Dto() - dto.resultAsDouble = Fisher.exe(m, n, x) - ResponseEntity.ok(dto) - } catch (e: RuntimeException) { - ResponseEntity.status(400).build() - } - } - - @GetMapping( - value = ["/gammq/{a}/{x}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun gammq( - @PathVariable("a") - @Parameter(description = "Shape a", required = true) - a: Double, - - @PathVariable("x") - @Parameter(description = "Argument x", required = true) - x: Double - ): ResponseEntity = - try { - val dto = Dto() - val gammq = Gammq() - dto.resultAsDouble = gammq.exe(a, x) - ResponseEntity.ok(dto) - } catch (e: RuntimeException) { - ResponseEntity.status(400).build() - } - - @GetMapping( - value = ["/remainder/{a}/{b}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun remainder( - @PathVariable("a") - @Parameter(description = "Dividend a (|a| ≤ 10000)", required = true) - a: Int, - - @PathVariable("b") - @Parameter(description = "Divisor b (|b| ≤ 10000)", required = true) - b: Int - ): ResponseEntity { - val lim = 10_000 - if (a > lim || a < -lim || b > lim || b < -lim) { - return ResponseEntity.status(400).build() - } - - val dto = Dto() - dto.resultAsInt = Remainder.exe(a, b) - return ResponseEntity.ok(dto) - } -} \ No newline at end of file diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Bessj.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Bessj.java deleted file mode 100644 index 45d5a6e571..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Bessj.java +++ /dev/null @@ -1,119 +0,0 @@ -package bar.examples.it.spring.aiclassification.ncs.imp; - -public class Bessj { - - private final double ACC = 40.0; - private final double BIGNO = 1.0e10; - private final double BIGNI = 1.0e-10; - - public double bessj(int n, double x) { - int j, jsum, m; - double ax, bj, bjm, bjp, sum, tox, ans; - - if (n < 2) - throw new IllegalArgumentException("Index n less than 2 in bessj"); - - ax = Math.abs(x); - - if (ax == 0.0) - return 0.0; - else if (ax > n) { - tox = 2.0 / ax; - bjm = bessj0(ax); - bj = bessj1(ax); - - for (j = 1; j < n; j++) { - bjp = j * tox * bj - bjm; - bjm = bj; - bj = bjp; - } - - ans = bj; - } else { - tox = 2.0 / ax; - m = 2 * ((n + (int) Math.round(Math.sqrt(ACC * n))) / 2); - jsum = 0; - bjp = ans = sum = 0.0; - bj = 1.0; - - for (j = m; j > 0; j--) { - bjm = j * tox * bj - bjp; - bjp = bj; - bj = bjm; - - if (Math.abs(bj) > BIGNO) { - bj *= BIGNI; - bjp *= BIGNI; - ans *= BIGNI; - sum *= BIGNI; - } - - if (jsum != 0) - sum += bj; - - jsum = (jsum != 0) ? 0 : 1; - - if (j == n) - ans = bjp; - } - - sum = 2.0 * sum - bj; - ans /= sum; - } - return x < 0.0 && (n & 1) != 0 ? -ans : ans; - } - - - private static double bessj0(double x) { - double ax, z; - double xx, y, ans, ans1, ans2; - - if ((ax = Math.abs(x)) < 8.0) { - y = x * x; - ans1 = 57568490574.0 + y * (-13362590354.0 + y * (651619640.7 - + y * (-11214424.18 + y * (77392.33017 + y * (-184.9052456))))); - ans2 = 57568490411.0 + y * (1029532985.0 + y * (9494680.718 - + y * (59272.64853 + y * (267.8532712 + y * 1.0)))); - ans = ans1 / ans2; - } else { - z = 8.0 / ax; - y = z * z; - xx = ax - 0.785398164; - ans1 = 1.0 + y * (-0.1098628627e-2 + y * (0.2734510407e-4 - + y * (-0.2073370639e-5 + y * 0.2093887211e-6))); - ans2 = -0.1562499995e-1 + y * (0.1430488765e-3 - + y * (-0.6911147651e-5 + y * (0.7621095161e-6 - - y * 0.934935152e-7))); - ans = Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2); - } - return ans; - } - - - private static double bessj1(double x) { - double ax, z; - double xx, y, ans, ans1, ans2; - - if ((ax = Math.abs(x)) < 8.0) { - y = x * x; - ans1 = x * (72362614232.0 + y * (-7895059235.0 + y * (242396853.1 - + y * (-2972611.439 + y * (15704.48260 + y * (-30.16036606)))))); - ans2 = 144725228442.0 + y * (2300535178.0 + y * (18583304.74 - + y * (99447.43394 + y * (376.9991397 + y * 1.0)))); - ans = ans1 / ans2; - } else { - z = 8.0 / ax; - y = z * z; - xx = ax - 2.356194491; - ans1 = 1.0 + y * (0.183105e-2 + y * (-0.3516396496e-4 - + y * (0.2457520174e-5 + y * (-0.240337019e-6)))); - ans2 = 0.04687499995 + y * (-0.2002690873e-3 - + y * (0.8449199096e-5 + y * (-0.88228987e-6 - + y * 0.105787412e-6))); - ans = Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2); - if (x < 0.0) ans = -ans; - } - - return ans; - } -} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Dto.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Dto.java deleted file mode 100644 index 576a341094..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Dto.java +++ /dev/null @@ -1,8 +0,0 @@ -package bar.examples.it.spring.aiclassification.ncs.imp; - -public class Dto { - - public Integer resultAsInt; - - public Double resultAsDouble; -} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Expint.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Expint.java deleted file mode 100644 index e7095538f3..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Expint.java +++ /dev/null @@ -1,76 +0,0 @@ -package bar.examples.it.spring.aiclassification.ncs.imp; - -public class Expint { - private static final double MAXIT = 100; - private static final double EULER = 0.5772156649; - private static final double FPMIN = 1.0e-30; - private static final double EPS = 1.0e-7; - - public static double exe(int n, double x) { - int i, ii, nm1; - double a, b, c, d, del, fact, h, psi, ans; - - nm1 = n - 1; - - if (n < 0 || x < 0.0 || (x == 0.0 && (n == 0 || n == 1))) - throw new RuntimeException("error: n < 0 or x < 0"); - else { - if (n == 0) - ans = Math.exp(-x) / x; - else { - if (x == 0.0) - ans = 1.0 / nm1; - else { - if (x > 1.0) { - b = x + n; - c = 1.0 / FPMIN; - d = 1.0 / b; - h = d; - - for (i = 1; i <= MAXIT; i++) { - a = -i * (nm1 + i); - b += 2.0; - d = 1.0 / (a * d + b); - c = b + a / c; - del = c * d; - h *= del; - - if (Math.abs(del - 1.0) < EPS) { - return h * Math.exp(-x); - } - } - - throw new RuntimeException("continued fraction failed in expint"); - } else { - ans = (nm1 != 0 ? 1.0 / nm1 : -Math.log(x) - EULER); - fact = 1.0; - - for (i = 1; i <= MAXIT; i++) { - fact *= -x / i; - - if (i != nm1) - del = -fact / (i - nm1); - else { - psi = -EULER; - - for (ii = 1; ii <= nm1; ii++) - psi += 1.0 / ii; - - del = fact * (-Math.log(x) + psi); - } - - ans += del; - - if (Math.abs(del) < Math.abs(ans) * EPS) { - return ans; - } - } - throw new RuntimeException("series failed in expint"); - } - } - } - } - return ans; - } -} - diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Fisher.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Fisher.java deleted file mode 100644 index df2f45fbfd..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Fisher.java +++ /dev/null @@ -1,63 +0,0 @@ -package bar.examples.it.spring.aiclassification.ncs.imp; - - - -public class Fisher { - public static double exe(int m, int n, double x) { - int a, b, i, j; - double w, y, z, zk, d, p; - - a = 2 * (m / 2) - m + 2; - b = 2 * (n / 2) - n + 2; - w = (x * m) / n; - z = 1.0 / (1.0 + w); - - if (a == 1) { - if (b == 1) { - p = Math.sqrt(w); - y = 0.3183098862; - d = y * z / p; - p = 2.0 * y * Math.atan(p); - } else { - p = Math.sqrt(w * z); - d = 0.5 * p * z / w; - } - } else if (b == 1) { - p = Math.sqrt(z); - d = 0.5 * z * p; - p = 1.0 - p; - } else { - d = z * z; - p = w * z; - } - - y = 2.0 * w / z; - - if (a == 1) - for (j = b + 2; j <= n; j += 2) { - d *= (1.0 + 1.0 / (j - 2)) * z; - p += d * y / (j - 1); - } - else { - zk = Math.pow(z, (double) ((n - 1) / 2)); - d *= (zk * n) / b; - p = p * zk + w * z * (zk - 1.0) / (z - 1.0); - } - - y = w * z; - z = 2.0 / z; - b = n - 2; - for (i = a + 2; i <= m; i += 2) { - j = i + b; - d *= (y * j) / (i - 2); - p -= z * d / j; - } - - if (p < 0.0) - return 0.0; - else if (p > 1.0) - return 1.0; - else - return p; - } -} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Gammq.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Gammq.java deleted file mode 100644 index 7b14a70e1f..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Gammq.java +++ /dev/null @@ -1,92 +0,0 @@ -package bar.examples.it.spring.aiclassification.ncs.imp; -public class Gammq { - private static final int ITMAX = 100; - private static final double EPS = 3.0e-7; - private static final double FPMIN = 1.0e-30; - - private double gamser, gammcf, gln; - - private double gammln(double xx) { - - double x,y,tmp,ser; - - double cof[] = {76.18009172947146,-86.50532032941677,24.01409824083091,-1.231739572450155,0.1208650973866179e-2,-0.5395239384953e-5}; - - int j; - - y=x=xx; - tmp=x+5.5; - tmp -= (x+0.5)*Math.log(tmp); - ser=1.000000000190015; - for (j=0;j<=5;j++) ser += cof[j]/++y; - return -tmp+Math.log(2.5066282746310005*ser/x); - } - - private void gcf(double a, double x) - { - int i; - double an,b,c,d,del,h; - - gln=gammln(a); - b=x+1.0-a; - c=1.0/FPMIN; - d=1.0/b; - h=d; - for (i=1;i<=ITMAX;i++) { - an = -i*(i-a); - b += 2.0; - d=an*d+b; - if (Math.abs(d) < FPMIN) d=FPMIN; - c=b+an/c; - if (Math.abs(c) < FPMIN) c=FPMIN; - d=1.0/d; - del=d*c; - h *= del; - if (Math.abs(del-1.0) < EPS) break; - } - if (i > ITMAX) throw new RuntimeException ("a too large, ITMAX too small in gcf"); - gammcf=Math.exp(-x+a*Math.log(x)-gln)*h; - } - - private void gser(double a, double x) { - - int n; - double sum,del,ap; - - gln=gammln(a); - - if (x <= 0.0) { - if (x < 0.0) throw new RuntimeException ("x less than 0 in routine gser"); - gamser=0.0; - return; - } - else { - ap=a; - del=sum=1.0/a; - for (n=1;n<=ITMAX;n++) { - ++ap; - del *= x/ap; - sum += del; - if (Math.abs(del) < Math.abs(sum)*EPS) { - gamser=sum*Math.exp(-x+a*Math.log(x)-gln); - return; - } - } - throw new RuntimeException ("a too large, ITMAX too small in routine gser"); - } - } - - public double exe(double a, double x) { - if (x < 0.0 || a <= 0.0) throw new RuntimeException("Invalid arguments in routine gammq"); - if (x < (a+1.0)) { - gser(a,x); - return 1-gamser; - } - else { - gcf(a,x); - return gammcf; - } - } - -} - diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Remainder.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Remainder.java deleted file mode 100644 index faee40abc4..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/Remainder.java +++ /dev/null @@ -1,42 +0,0 @@ -package bar.examples.it.spring.aiclassification.ncs.imp; - -public class Remainder { - public static int exe(int a, int b) { - int r = 0 - 1; - int cy = 0; - int ny = 0; - - if (a == 0) ; - else if (b == 0) ; - else if (a > 0) - if (b > 0) - while ((a - ny) >= b) { - ny = ny + b; - r = a - ny; - cy = cy + 1; - } - else // b<0 - //while((a+ny)>=Math.abs(b)) - while ((a + ny) >= ((b >= 0) ? b : -b)) { - ny = ny + b; - r = a + ny; - cy = cy - 1; - } - else // a<0 - if (b > 0) - //while(Math.abs(a+ny)>=b) - while (((a + ny) >= 0 ? (a + ny) : -(a + ny)) >= b) { - ny = ny + b; - r = a + ny; - cy = cy - 1; - } - else - while (b >= (a - ny)) { - ny = ny + b; - //r=Math.abs(a-ny); - r = ((a - ny) >= 0 ? (a - ny) : -(a - ny)); - cy = cy + 1; - } - return r; - } -} \ No newline at end of file diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/TriangleClassification.java b/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/TriangleClassification.java deleted file mode 100644 index b0a9437ab2..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/aiclassification/ncs/imp/TriangleClassification.java +++ /dev/null @@ -1,29 +0,0 @@ -package bar.examples.it.spring.aiclassification.ncs.imp; - -public class TriangleClassification { - - public static int classify(int a, int b, int c) { - - if (a <= 0 || b <= 0 || c <= 0) { - return 0; - } - - if (a == b && b == c) { - return 3; - } - - int max = Math.max(a, Math.max(b, c)); - - if ((max == a && max - b - c >= 0) || - (max == b && max - a - c >= 0) || - (max == c && max - a - b >= 0)) { - return 0; - } - - if (a == b || b == c || a == c) { - return 2; - } else { - return 1; - } - } -} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/NCSApplication.kt b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/NCSApplication.kt deleted file mode 100644 index 5a35ad9fa7..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/NCSApplication.kt +++ /dev/null @@ -1,174 +0,0 @@ -package bar.examples.it.spring.ncs - -import bar.examples.it.spring.ncs.imp.Bessj -import bar.examples.it.spring.ncs.imp.Dto -import bar.examples.it.spring.ncs.imp.Expint -import bar.examples.it.spring.ncs.imp.Fisher -import bar.examples.it.spring.ncs.imp.Gammq -import bar.examples.it.spring.ncs.imp.Remainder -import bar.examples.it.spring.ncs.imp.TriangleClassification -import io.swagger.v3.oas.annotations.Parameter -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration -import org.springframework.http.MediaType -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController - -@SpringBootApplication(exclude = [SecurityAutoConfiguration::class]) -@RestController -@RequestMapping(path = ["/api"]) -open class NCSApplication { - - companion object { - @JvmStatic - fun main(args: Array) { - SpringApplication.run(NCSApplication::class.java, *args) - } - } - - @GetMapping( - value = ["/triangle/{a}/{b}/{c}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun checkTriangle( - @PathVariable("a") - @Parameter(description = "First edge", required = true) - a: Int, - - @PathVariable("b") - @Parameter(description = "Second edge", required = true) - b: Int, - - @PathVariable("c") - @Parameter(description = "Third edge", required = true) - c: Int - ): ResponseEntity { - - val dto = Dto() - dto.resultAsInt = TriangleClassification.classify(a, b, c) - return ResponseEntity.ok(dto) - } - - @GetMapping( - value = ["/bessj/{n}/{x}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun bessj( - @PathVariable("n") - @Parameter(description = "Order n (2 < n ≤ 1000)", required = true) - n: Int, - - @PathVariable("x") - @Parameter(description = "Argument x", required = true) - x: Double - ): ResponseEntity { - if (n <= 2 || n > 1000) { - return ResponseEntity.status(400).build() - } - - val dto = Dto() - val bessj = Bessj() - dto.resultAsDouble = bessj.bessj(n, x) - return ResponseEntity.ok(dto) - } - - @GetMapping( - value = ["/expint/{n}/{x}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun expint( - @PathVariable("n") - @Parameter(description = "Order n", required = true) - n: Int, - - @PathVariable("x") - @Parameter(description = "Argument x", required = true) - x: Double - ): ResponseEntity = - try { - val dto = Dto() - dto.resultAsDouble = Expint.exe(n, x) - ResponseEntity.ok(dto) - } catch (e: RuntimeException) { - ResponseEntity.status(400).build() - } - - @GetMapping( - value = ["/fisher/{m}/{n}/{x}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun fisher( - @PathVariable("m") - @Parameter(description = "Degrees of freedom m (≤ 1000)", required = true) - m: Int, - - @PathVariable("n") - @Parameter(description = "Degrees of freedom n (≤ 1000)", required = true) - n: Int, - - @PathVariable("x") - @Parameter(description = "Argument x", required = true) - x: Double - ): ResponseEntity { - if (m > 1000 || n > 1000) { - return ResponseEntity.status(400).build() - } - - return try { - val dto = Dto() - dto.resultAsDouble = Fisher.exe(m, n, x) - ResponseEntity.ok(dto) - } catch (e: RuntimeException) { - ResponseEntity.status(400).build() - } - } - - @GetMapping( - value = ["/gammq/{a}/{x}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun gammq( - @PathVariable("a") - @Parameter(description = "Shape a", required = true) - a: Double, - - @PathVariable("x") - @Parameter(description = "Argument x", required = true) - x: Double - ): ResponseEntity = - try { - val dto = Dto() - val gammq = Gammq() - dto.resultAsDouble = gammq.exe(a, x) - ResponseEntity.ok(dto) - } catch (e: RuntimeException) { - ResponseEntity.status(400).build() - } - - @GetMapping( - value = ["/remainder/{a}/{b}"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - open fun remainder( - @PathVariable("a") - @Parameter(description = "Dividend a (|a| ≤ 10000)", required = true) - a: Int, - - @PathVariable("b") - @Parameter(description = "Divisor b (|b| ≤ 10000)", required = true) - b: Int - ): ResponseEntity { - val lim = 10_000 - if (a > lim || a < -lim || b > lim || b < -lim) { - return ResponseEntity.status(400).build() - } - - val dto = Dto() - dto.resultAsInt = Remainder.exe(a, b) - return ResponseEntity.ok(dto) - } -} \ No newline at end of file diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Bessj.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Bessj.java deleted file mode 100644 index cd160c762c..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Bessj.java +++ /dev/null @@ -1,119 +0,0 @@ -package bar.examples.it.spring.ncs.imp; - -public class Bessj { - - private final double ACC = 40.0; - private final double BIGNO = 1.0e10; - private final double BIGNI = 1.0e-10; - - public double bessj(int n, double x) { - int j, jsum, m; - double ax, bj, bjm, bjp, sum, tox, ans; - - if (n < 2) - throw new IllegalArgumentException("Index n less than 2 in bessj"); - - ax = Math.abs(x); - - if (ax == 0.0) - return 0.0; - else if (ax > n) { - tox = 2.0 / ax; - bjm = bessj0(ax); - bj = bessj1(ax); - - for (j = 1; j < n; j++) { - bjp = j * tox * bj - bjm; - bjm = bj; - bj = bjp; - } - - ans = bj; - } else { - tox = 2.0 / ax; - m = 2 * ((n + (int) Math.round(Math.sqrt(ACC * n))) / 2); - jsum = 0; - bjp = ans = sum = 0.0; - bj = 1.0; - - for (j = m; j > 0; j--) { - bjm = j * tox * bj - bjp; - bjp = bj; - bj = bjm; - - if (Math.abs(bj) > BIGNO) { - bj *= BIGNI; - bjp *= BIGNI; - ans *= BIGNI; - sum *= BIGNI; - } - - if (jsum != 0) - sum += bj; - - jsum = (jsum != 0) ? 0 : 1; - - if (j == n) - ans = bjp; - } - - sum = 2.0 * sum - bj; - ans /= sum; - } - return x < 0.0 && (n & 1) != 0 ? -ans : ans; - } - - - private static double bessj0(double x) { - double ax, z; - double xx, y, ans, ans1, ans2; - - if ((ax = Math.abs(x)) < 8.0) { - y = x * x; - ans1 = 57568490574.0 + y * (-13362590354.0 + y * (651619640.7 - + y * (-11214424.18 + y * (77392.33017 + y * (-184.9052456))))); - ans2 = 57568490411.0 + y * (1029532985.0 + y * (9494680.718 - + y * (59272.64853 + y * (267.8532712 + y * 1.0)))); - ans = ans1 / ans2; - } else { - z = 8.0 / ax; - y = z * z; - xx = ax - 0.785398164; - ans1 = 1.0 + y * (-0.1098628627e-2 + y * (0.2734510407e-4 - + y * (-0.2073370639e-5 + y * 0.2093887211e-6))); - ans2 = -0.1562499995e-1 + y * (0.1430488765e-3 - + y * (-0.6911147651e-5 + y * (0.7621095161e-6 - - y * 0.934935152e-7))); - ans = Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2); - } - return ans; - } - - - private static double bessj1(double x) { - double ax, z; - double xx, y, ans, ans1, ans2; - - if ((ax = Math.abs(x)) < 8.0) { - y = x * x; - ans1 = x * (72362614232.0 + y * (-7895059235.0 + y * (242396853.1 - + y * (-2972611.439 + y * (15704.48260 + y * (-30.16036606)))))); - ans2 = 144725228442.0 + y * (2300535178.0 + y * (18583304.74 - + y * (99447.43394 + y * (376.9991397 + y * 1.0)))); - ans = ans1 / ans2; - } else { - z = 8.0 / ax; - y = z * z; - xx = ax - 2.356194491; - ans1 = 1.0 + y * (0.183105e-2 + y * (-0.3516396496e-4 - + y * (0.2457520174e-5 + y * (-0.240337019e-6)))); - ans2 = 0.04687499995 + y * (-0.2002690873e-3 - + y * (0.8449199096e-5 + y * (-0.88228987e-6 - + y * 0.105787412e-6))); - ans = Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2); - if (x < 0.0) ans = -ans; - } - - return ans; - } -} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Dto.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Dto.java deleted file mode 100644 index 66fe35069c..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Dto.java +++ /dev/null @@ -1,8 +0,0 @@ -package bar.examples.it.spring.ncs.imp; - -public class Dto { - - public Integer resultAsInt; - - public Double resultAsDouble; -} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Expint.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Expint.java deleted file mode 100644 index 23219c193b..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Expint.java +++ /dev/null @@ -1,76 +0,0 @@ -package bar.examples.it.spring.ncs.imp; - -public class Expint { - private static final double MAXIT = 100; - private static final double EULER = 0.5772156649; - private static final double FPMIN = 1.0e-30; - private static final double EPS = 1.0e-7; - - public static double exe(int n, double x) { - int i, ii, nm1; - double a, b, c, d, del, fact, h, psi, ans; - - nm1 = n - 1; - - if (n < 0 || x < 0.0 || (x == 0.0 && (n == 0 || n == 1))) - throw new RuntimeException("error: n < 0 or x < 0"); - else { - if (n == 0) - ans = Math.exp(-x) / x; - else { - if (x == 0.0) - ans = 1.0 / nm1; - else { - if (x > 1.0) { - b = x + n; - c = 1.0 / FPMIN; - d = 1.0 / b; - h = d; - - for (i = 1; i <= MAXIT; i++) { - a = -i * (nm1 + i); - b += 2.0; - d = 1.0 / (a * d + b); - c = b + a / c; - del = c * d; - h *= del; - - if (Math.abs(del - 1.0) < EPS) { - return h * Math.exp(-x); - } - } - - throw new RuntimeException("continued fraction failed in expint"); - } else { - ans = (nm1 != 0 ? 1.0 / nm1 : -Math.log(x) - EULER); - fact = 1.0; - - for (i = 1; i <= MAXIT; i++) { - fact *= -x / i; - - if (i != nm1) - del = -fact / (i - nm1); - else { - psi = -EULER; - - for (ii = 1; ii <= nm1; ii++) - psi += 1.0 / ii; - - del = fact * (-Math.log(x) + psi); - } - - ans += del; - - if (Math.abs(del) < Math.abs(ans) * EPS) { - return ans; - } - } - throw new RuntimeException("series failed in expint"); - } - } - } - } - return ans; - } -} - diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Fisher.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Fisher.java deleted file mode 100644 index 38863945ae..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Fisher.java +++ /dev/null @@ -1,63 +0,0 @@ -package bar.examples.it.spring.ncs.imp; - - - -public class Fisher { - public static double exe(int m, int n, double x) { - int a, b, i, j; - double w, y, z, zk, d, p; - - a = 2 * (m / 2) - m + 2; - b = 2 * (n / 2) - n + 2; - w = (x * m) / n; - z = 1.0 / (1.0 + w); - - if (a == 1) { - if (b == 1) { - p = Math.sqrt(w); - y = 0.3183098862; - d = y * z / p; - p = 2.0 * y * Math.atan(p); - } else { - p = Math.sqrt(w * z); - d = 0.5 * p * z / w; - } - } else if (b == 1) { - p = Math.sqrt(z); - d = 0.5 * z * p; - p = 1.0 - p; - } else { - d = z * z; - p = w * z; - } - - y = 2.0 * w / z; - - if (a == 1) - for (j = b + 2; j <= n; j += 2) { - d *= (1.0 + 1.0 / (j - 2)) * z; - p += d * y / (j - 1); - } - else { - zk = Math.pow(z, (double) ((n - 1) / 2)); - d *= (zk * n) / b; - p = p * zk + w * z * (zk - 1.0) / (z - 1.0); - } - - y = w * z; - z = 2.0 / z; - b = n - 2; - for (i = a + 2; i <= m; i += 2) { - j = i + b; - d *= (y * j) / (i - 2); - p -= z * d / j; - } - - if (p < 0.0) - return 0.0; - else if (p > 1.0) - return 1.0; - else - return p; - } -} diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Gammq.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Gammq.java deleted file mode 100644 index b897cfe9e3..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Gammq.java +++ /dev/null @@ -1,92 +0,0 @@ -package bar.examples.it.spring.ncs.imp; -public class Gammq { - private static final int ITMAX = 100; - private static final double EPS = 3.0e-7; - private static final double FPMIN = 1.0e-30; - - private double gamser, gammcf, gln; - - private double gammln(double xx) { - - double x,y,tmp,ser; - - double cof[] = {76.18009172947146,-86.50532032941677,24.01409824083091,-1.231739572450155,0.1208650973866179e-2,-0.5395239384953e-5}; - - int j; - - y=x=xx; - tmp=x+5.5; - tmp -= (x+0.5)*Math.log(tmp); - ser=1.000000000190015; - for (j=0;j<=5;j++) ser += cof[j]/++y; - return -tmp+Math.log(2.5066282746310005*ser/x); - } - - private void gcf(double a, double x) - { - int i; - double an,b,c,d,del,h; - - gln=gammln(a); - b=x+1.0-a; - c=1.0/FPMIN; - d=1.0/b; - h=d; - for (i=1;i<=ITMAX;i++) { - an = -i*(i-a); - b += 2.0; - d=an*d+b; - if (Math.abs(d) < FPMIN) d=FPMIN; - c=b+an/c; - if (Math.abs(c) < FPMIN) c=FPMIN; - d=1.0/d; - del=d*c; - h *= del; - if (Math.abs(del-1.0) < EPS) break; - } - if (i > ITMAX) throw new RuntimeException ("a too large, ITMAX too small in gcf"); - gammcf=Math.exp(-x+a*Math.log(x)-gln)*h; - } - - private void gser(double a, double x) { - - int n; - double sum,del,ap; - - gln=gammln(a); - - if (x <= 0.0) { - if (x < 0.0) throw new RuntimeException ("x less than 0 in routine gser"); - gamser=0.0; - return; - } - else { - ap=a; - del=sum=1.0/a; - for (n=1;n<=ITMAX;n++) { - ++ap; - del *= x/ap; - sum += del; - if (Math.abs(del) < Math.abs(sum)*EPS) { - gamser=sum*Math.exp(-x+a*Math.log(x)-gln); - return; - } - } - throw new RuntimeException ("a too large, ITMAX too small in routine gser"); - } - } - - public double exe(double a, double x) { - if (x < 0.0 || a <= 0.0) throw new RuntimeException("Invalid arguments in routine gammq"); - if (x < (a+1.0)) { - gser(a,x); - return 1-gamser; - } - else { - gcf(a,x); - return gammcf; - } - } - -} - diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Remainder.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Remainder.java deleted file mode 100644 index f5f565bf54..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/Remainder.java +++ /dev/null @@ -1,42 +0,0 @@ -package bar.examples.it.spring.ncs.imp; - -public class Remainder { - public static int exe(int a, int b) { - int r = 0 - 1; - int cy = 0; - int ny = 0; - - if (a == 0) ; - else if (b == 0) ; - else if (a > 0) - if (b > 0) - while ((a - ny) >= b) { - ny = ny + b; - r = a - ny; - cy = cy + 1; - } - else // b<0 - //while((a+ny)>=Math.abs(b)) - while ((a + ny) >= ((b >= 0) ? b : -b)) { - ny = ny + b; - r = a + ny; - cy = cy - 1; - } - else // a<0 - if (b > 0) - //while(Math.abs(a+ny)>=b) - while (((a + ny) >= 0 ? (a + ny) : -(a + ny)) >= b) { - ny = ny + b; - r = a + ny; - cy = cy - 1; - } - else - while (b >= (a - ny)) { - ny = ny + b; - //r=Math.abs(a-ny); - r = ((a - ny) >= 0 ? (a - ny) : -(a - ny)); - cy = cy + 1; - } - return r; - } -} \ No newline at end of file diff --git a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/TriangleClassification.java b/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/TriangleClassification.java deleted file mode 100644 index 22adc0d1d5..0000000000 --- a/core-it/src/main/kotlin/bar/examples/it/spring/ncs/imp/TriangleClassification.java +++ /dev/null @@ -1,29 +0,0 @@ -package bar.examples.it.spring.ncs.imp; - -public class TriangleClassification { - - public static int classify(int a, int b, int c) { - - if (a <= 0 || b <= 0 || c <= 0) { - return 0; - } - - if (a == b && b == c) { - return 3; - } - - int max = Math.max(a, Math.max(b, c)); - - if ((max == a && max - b - c >= 0) || - (max == b && max - a - c >= 0) || - (max == c && max - a - b >= 0)) { - return 0; - } - - if (a == b || b == c || a == c) { - return 2; - } else { - return 1; - } - } -} diff --git a/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSController.kt b/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSController.kt deleted file mode 100644 index 7ff02ac9d2..0000000000 --- a/core-it/src/test/kotlin/bar/examples/it/spring/aiclassification/ncs/NCSController.kt +++ /dev/null @@ -1,6 +0,0 @@ -package bar.examples.it.spring.aiclassification.ncs - -import bar.examples.it.spring.SpringController - -class NCSController : SpringController(NCSApplication::class.java) - diff --git a/core-it/src/test/kotlin/bar/examples/it/spring/ncs/NCSController.kt b/core-it/src/test/kotlin/bar/examples/it/spring/ncs/NCSController.kt deleted file mode 100644 index 0e4edd3296..0000000000 --- a/core-it/src/test/kotlin/bar/examples/it/spring/ncs/NCSController.kt +++ /dev/null @@ -1,6 +0,0 @@ -package bar.examples.it.spring.ncs - -import bar.examples.it.spring.SpringController - -class NCSController : SpringController(NCSApplication::class.java) - diff --git a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt index 216b5923c9..4f27139953 100644 --- a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt +++ b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt @@ -2,7 +2,6 @@ package org.evomaster.core.problem.rest.aiclassification import bar.examples.it.spring.aiclassification.basic.BasicController import bar.examples.it.spring.aiclassification.multitype.MultiTypeController -import bar.examples.it.spring.aiclassification.ncs.NCSController import org.evomaster.core.problem.enterprise.SampleType import org.evomaster.core.problem.rest.IntegrationTestRestBase import org.evomaster.core.problem.rest.data.RestCallAction @@ -32,9 +31,8 @@ class AIGLMCheck : IntegrationTestRestBase() { companion object { @JvmStatic fun init() { - initClass(NCSController()) // initClass(BasicController()) -// initClass(MultiTypeController()) + initClass(MultiTypeController()) } @JvmStatic @@ -72,7 +70,7 @@ class AIGLMCheck : IntegrationTestRestBase() { val body = connection.inputStream.bufferedReader().use { it.readText() } result.setBody(body) - result.setBodyType(MediaType.APPLICATION_JSON_TYPE) // or guess based on Content-Type header + result.setBodyType(MediaType.APPLICATION_JSON_TYPE) // or guess based on the Content-Type header } catch (e: Exception) { result.setTimedout(true) diff --git a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt index cab0da7890..844859e282 100644 --- a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt +++ b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt @@ -2,7 +2,6 @@ package org.evomaster.core.problem.rest.aiclassification import bar.examples.it.spring.aiclassification.basic.BasicController import bar.examples.it.spring.aiclassification.multitype.MultiTypeController -import bar.examples.it.spring.aiclassification.ncs.NCSController import org.evomaster.core.problem.enterprise.SampleType import org.evomaster.core.problem.rest.IntegrationTestRestBase import org.evomaster.core.problem.rest.data.RestCallAction @@ -32,8 +31,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { companion object { @JvmStatic fun init() { - initClass(NCSController()) -// initClass(BasicController()) + initClass(BasicController()) // initClass(MultiTypeController()) } @@ -67,7 +65,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { val body = connection.inputStream.bufferedReader().use { it.readText() } result.setBody(body) - result.setBodyType(MediaType.APPLICATION_JSON_TYPE) // or guess based on Content-Type header + result.setBodyType(MediaType.APPLICATION_JSON_TYPE) // or guess based on the Content-Type header } catch (e: Exception) { result.setTimedout(true) From f3ceda38af0729519a6a5979f5f1719255b423f5 Mon Sep 17 00:00:00 2001 From: Mohsen Taheri Shalmani Date: Fri, 29 Aug 2025 12:43:27 +0200 Subject: [PATCH 5/7] Debugging and improvement --- .../rest/aiclassification/AIGLMCheck.kt | 42 ++- .../rest/aiclassification/AIGaussianCheck.kt | 45 ++-- .../classifier/AIResponseClassification.kt | 15 ++ .../rest/classifier/ClassifierPerformance.kt | 25 ++ .../classifier/GaussianOnlineClassifier.kt | 112 ++++---- .../rest/classifier/GeneralizedLinearModel.kt | 101 ++++---- .../core/output/TestSuiteOrganizerTest.kt | 239 ++++++++++++++++++ 7 files changed, 420 insertions(+), 159 deletions(-) create mode 100644 core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/ClassifierPerformance.kt diff --git a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt index 4f27139953..09409554f9 100644 --- a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt +++ b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGLMCheck.kt @@ -31,8 +31,8 @@ class AIGLMCheck : IntegrationTestRestBase() { companion object { @JvmStatic fun init() { -// initClass(BasicController()) - initClass(MultiTypeController()) + initClass(BasicController()) +// initClass(MultiTypeController()) } @JvmStatic @@ -103,7 +103,7 @@ class AIGLMCheck : IntegrationTestRestBase() { val name = action.getName() val hasUnsupportedGene = action.parameters.any { p -> - val g = p.gene.getLeafGene() + val g = p.primaryGene().getLeafGene() g !is IntegerGene && g !is DoubleGene && g !is BooleanGene && g !is EnumGene<*> } @@ -111,7 +111,7 @@ class AIGLMCheck : IntegrationTestRestBase() { null } else { action.parameters.count { p -> - val g = p.gene.getLeafGene() + val g = p.primaryGene().getLeafGene() g is IntegerGene || g is DoubleGene || g is BooleanGene || g is EnumGene<*> } } @@ -131,7 +131,7 @@ class AIGLMCheck : IntegrationTestRestBase() { endpointToClassifier[name] = null }else{ val model = GLMOnlineClassifier() - model.setDimension(dimension) + model.setup(dimension=dimension, warmup = 10) endpointToClassifier[name] = model } } @@ -153,7 +153,7 @@ class AIGLMCheck : IntegrationTestRestBase() { val name = sampledAction.getName() val classifier = endpointToClassifier[name] val dimension = endpointToDimension[name] - val geneValues = sampledAction.parameters.map { it.gene.getValueAsRawString() } + val geneValues = sampledAction.parameters.map { it.primaryGene().getValueAsRawString() } println("*************************************************") println("Path : $name") @@ -161,7 +161,10 @@ class AIGLMCheck : IntegrationTestRestBase() { println("Dimension : $dimension") println("Input Genes : ${geneValues.joinToString(", ")}") println("Genes Size : ${geneValues.size}") - println("cp, tot, ac : ${classifier?.getCorrectPredictions()}, ${classifier?.getTotalRequests()}, ${classifier?.getAccuracy()}") + println("Correct Predictions: ${classifier?.performance?.correctPrediction}") + println("Total Requests : ${classifier?.performance?.totalSentRequests}") + println("Accuracy : ${classifier?.performance?.accuracy()}") + // executeRestCallAction is replaced with createIndividual to avoid override error // val individual = createIndividual(listOf(sampledAction), SampleType.RANDOM) @@ -175,13 +178,11 @@ class AIGLMCheck : IntegrationTestRestBase() { continue } // Warmup cold classifiers by at least n request - val n = 2 - val isCold = classifier.getTotalRequests() <= n + val isCold = classifier.performance.totalSentRequests p400) 200 else 400 - println("Prediction is : $prediction") + val predictionOfStatusCode = classification.prediction() + println("Prediction is : $predictionOfStatusCode") // Probabilistic decision-making based on Bernoulli(prob = aci) val sendOrNot: Boolean - if (prediction != 400) { + if (predictionOfStatusCode != 400) { sendOrNot = true }else{ - sendOrNot = if(Math.random() > classifier.getAccuracy()) true else false + sendOrNot = if(Math.random() > classifier.performance.accuracy()) true else false } // Execute the request and update @@ -213,10 +209,8 @@ class AIGLMCheck : IntegrationTestRestBase() { val result = executeRestCallAction(action,"$baseUrlOfSut") println("Response : ${result.getStatusCode()}") - if (result.getStatusCode()==prediction) { - classifier.setCp(classifier.getCorrectPredictions() + 1) - } - classifier.setTot(classifier.getTotalRequests() + 1) + println("Updating the classifier!") + classifier.updateModel(action, result) println("Updating the classifier!") classifier.updateModel(action, result) diff --git a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt index 844859e282..e9bace6f87 100644 --- a/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt +++ b/core-it/src/test/kotlin/org/evomaster/core/problem/rest/aiclassification/AIGaussianCheck.kt @@ -23,7 +23,6 @@ import java.net.HttpURLConnection import java.net.URL import javax.ws.rs.core.MediaType import kotlin.collections.iterator -import kotlin.math.abs class AIGaussianCheck : IntegrationTestRestBase() { @@ -98,7 +97,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { val name = action.getName() val hasUnsupportedGene = action.parameters.any { p -> - val g = p.gene.getLeafGene() + val g = p.primaryGene().getLeafGene() println("Parameter: ${p.name}, Gene: ${g::class.simpleName}") g !is IntegerGene && g !is DoubleGene && g !is BooleanGene && g !is EnumGene<*> } @@ -107,7 +106,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { null } else { action.parameters.count { p -> - val g = p.gene.getLeafGene() + val g = p.primaryGene().getLeafGene() g is IntegerGene || g is DoubleGene || g is BooleanGene || g is EnumGene<*> } } @@ -126,7 +125,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { endpointToClassifier[name] = null }else{ val model = GaussianOnlineClassifier() - model.setDimension(dimension) + model.setup(dimension=dimension, warmup = 10) endpointToClassifier[name] = model } } @@ -148,7 +147,7 @@ class AIGaussianCheck : IntegrationTestRestBase() { val name = sampledAction.getName() val classifier = endpointToClassifier[name] val dimension = endpointToDimension[name] - val geneValues = sampledAction.parameters.map { it.gene.getValueAsRawString()} + val geneValues = sampledAction.parameters.map { it.primaryGene().getValueAsRawString()} println("*************************************************") println("Path : $name") @@ -156,7 +155,9 @@ class AIGaussianCheck : IntegrationTestRestBase() { println("Dimension : $dimension") println("Input Genes : ${geneValues.joinToString(", ")}") println("Genes Size : ${geneValues.size}") - println("cp, tot, ac : ${classifier?.getCorrectPredictions()}, ${classifier?.getTotalRequests()}, ${classifier?.getAccuracy()}") + println("Correct Predictions: ${classifier?.performance?.correctPrediction}") + println("Total Requests : ${classifier?.performance?.totalSentRequests}") + println("Accuracy : ${classifier?.performance?.accuracy()}") // executeRestCallAction is replaced with createIndividual to avoid override error // val individual = createIndividual(listOf(sampledAction), SampleType.RANDOM) @@ -169,15 +170,13 @@ class AIGaussianCheck : IntegrationTestRestBase() { println("No classification as the classifier is null, i.e., the endpoint contains unsupported genes") continue } + // Warmup cold classifiers by at least n request - val n = 2 - val isCold = classifier.getTotalRequests() <= n + val isCold = classifier.performance.totalSentRequests p400) 200 else 400 - println("Prediction is : $prediction") + val predictionOfStatusCode = classification.prediction() + println("Prediction is : $predictionOfStatusCode") // Probabilistic decision-making based on Bernoulli(prob = aci) val sendOrNot: Boolean - if (prediction != 400) { + if (predictionOfStatusCode != 400) { sendOrNot = true }else{ - sendOrNot = if(Math.random() > classifier.getAccuracy()) true else false + sendOrNot = if(Math.random() > classifier.performance.accuracy()) true else false } // Execute the request and update @@ -209,21 +203,16 @@ class AIGaussianCheck : IntegrationTestRestBase() { val result = executeRestCallAction(action,"$baseUrlOfSut") println("Response : ${result.getStatusCode()}") - if (result.getStatusCode()==prediction) { - classifier.setCp(classifier.getCorrectPredictions() + 1) - } - classifier.setTot(classifier.getTotalRequests() + 1) - println("Updating the classifier!") classifier.updateModel(action, result) - val d200 = classifier.getDensity200() - val d400 = classifier.getDensity400() + val d200 = classifier.density200!! + val d400 = classifier.density400!! fun formatStats(name: String, mean: List, variance: List, n: Int) { val m = mean.map { "%.2f".format(it) } val v = variance.map { "%.2f".format(it) } - println("$name: n=$n, mean=$m, variance=$v * I_${classifier.getDimension()}") + println("$name: n=$n, mean=$m, variance=$v * I_${classifier.dimension}") } formatStats("Density200", d200.mean, d200.variance, d200.n) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/AIResponseClassification.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/AIResponseClassification.kt index 9ba4436a6c..6eb9ce6a1b 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/AIResponseClassification.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/AIResponseClassification.kt @@ -15,6 +15,13 @@ class AIResponseClassification( " But status code ${it.key} has probability value ${it.value}") } } + + val sum = probabilities.values.sum() + if (kotlin.math.abs(sum - 1.0) > 1e-6) { + throw IllegalArgumentException( + "Probabilities must sum to 1." + ) + } } fun probabilityOf400() : Double{ @@ -24,4 +31,12 @@ class AIResponseClassification( } return probabilities[400]!! } + + /** + * Returns the status code with the highest probability. + * @return the status code (key) with maximum probability + */ + fun prediction(): Int { + return probabilities.maxByOrNull { it.value }?.key ?: -1 + } } \ No newline at end of file diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/ClassifierPerformance.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/ClassifierPerformance.kt new file mode 100644 index 0000000000..70819cff27 --- /dev/null +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/ClassifierPerformance.kt @@ -0,0 +1,25 @@ +package org.evomaster.core.problem.rest.classifier + +/** + * Classifier state + * + * @param correctPrediction the number of correct predictions made by the classifier + * @param totalSentRequests the total number of requests sent to the classifier + */ +class ClassifierPerformance( + val correctPrediction: Int, + val totalSentRequests: Int +) { + + /** + * Calculates the accuracy of the classifier. + * @return the ratio of correct predictions to total requests. + */ + fun accuracy(): Double { + return if (totalSentRequests > 0) { + correctPrediction.toDouble() / totalSentRequests + } else { + 0.0 + } + } +} diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt index 3b7ea63889..9482a554d1 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt @@ -29,69 +29,40 @@ import kotlin.math.exp * - The only two supported classes are 200 and 400. * * @param dimension the fixed dimensionality of the input feature vectors. + * @param warmup the number of warmup updates to familiarize the classifier with at least a few true observations */ class GaussianOnlineClassifier : AIModel { - private var dimension: Int? = null - private var density200: Density? = null - private var density400: Density? = null - - // classifier state - private var cp: Int = 0 // correct predictions - private var tot: Int = 1 // total requests - private var ac: Double = 0.0 // accuracy ratio - - fun setDimension(d: Int) { - require(d > 0) { "Dimension must be positive." } - this.dimension = d - this.density200 = Density(d) - this.density400 = Density(d) - this.cp = 0 - this.tot = 1 - this.ac = 0.0 + var warmup: Int = 10 + var dimension: Int? = null + var density200: Density? = null + var density400: Density? = null + var performance: ClassifierPerformance = ClassifierPerformance(0, 1) + + /** Must be called once to initialize the model properties */ + fun setup(dimension: Int, warmup: Int) { + require(dimension > 0 ) { "Dimension must be positive." } + this.dimension = dimension + this.density200 = Density(dimension) + this.density400 = Density(dimension) + require(warmup > 0 ) { "Warmup must be positive." } + this.warmup = warmup + this.performance = ClassifierPerformance(0, 1) } - fun getDimension(): Int { - check(this.dimension != null) { "Classifier not initialized. Call setDimension first." } - return this.dimension!! + fun updatePerformance(predictionIsCorrect: Boolean) { + val totalCorrectPredictions = if (predictionIsCorrect) performance.correctPrediction + 1 else performance.correctPrediction + val totalSentRequests = performance.totalSentRequests + 1 + this.performance = ClassifierPerformance(totalCorrectPredictions, totalSentRequests) } - fun setCp(cp: Int) { - this.cp = cp - } - fun setTot(tot: Int){ - this.tot = tot - } - - fun getCorrectPredictions(): Int = cp - fun getTotalRequests(): Int = tot - fun getAccuracy(): Double = if (tot == 0) 0.0 else cp.toDouble() / tot - - fun getDensity200(): Density { - check(this.density200 != null) { "Classifier not initialized. Call setDimension first." } - return this.density200!! - } - - fun getDensity400(): Density { - check(this.density400 != null) { "Classifier not initialized. Call setDimension first." } - return this.density400!! - } - - override fun updateModel(input: RestCallAction, output: RestCallResult) { - val inputVector = InputEncoderUtils.encode(input).normalizedEncodedFeatures - if (inputVector.size != this.dimension) { - throw IllegalArgumentException("Expected input vector of size ${this.dimension} but got ${inputVector.size}") - } + override fun classify(input: RestCallAction): AIResponseClassification { - when (output.getStatusCode()) { - 200 -> this.density200!!.update(inputVector) - 400 -> this.density400!!.update(inputVector) - else -> throw IllegalArgumentException("Label must be G_2xx or G_4xx") + if (performance.totalSentRequests < warmup) { + throw IllegalStateException("Classifier not ready as warmup is not completed.") } - } - override fun classify(input: RestCallAction): AIResponseClassification { val inputVector = InputEncoderUtils.encode(input).normalizedEncodedFeatures if (inputVector.size != this.dimension) { @@ -118,13 +89,38 @@ class GaussianOnlineClassifier : AIModel { ) } - override fun estimateAccuracy(endpoint: Endpoint): Double { - // Strict accuracy - //TODO this accuracy can be dynamic for example based on the last 100 requests - if (this.tot == 0) { - return 0.0 + override fun updateModel(input: RestCallAction, output: RestCallResult) { + val inputVector = InputEncoderUtils.encode(input).normalizedEncodedFeatures + + if (inputVector.size != this.dimension) { + throw IllegalArgumentException("Expected input vector of size ${this.dimension} but got ${inputVector.size}") + } + + /** + * Updating classifier performance based on its prediction + * The performance getting update only after the warmup procedure + */ + val trueStatusCode = output.getStatusCode() + if (this.performance.totalSentRequests <= this.warmup) { + updatePerformance(predictionIsCorrect = false) + }else{ + val predicted = classify(input).prediction() + updatePerformance(predictionIsCorrect = (predicted == trueStatusCode)) } - return this.cp.toDouble() / this.tot + + /** + * Updating the density functions based on the real observation + */ + when (trueStatusCode) { + 200 -> this.density200!!.update(inputVector) + 400 -> this.density400!!.update(inputVector) + else -> throw IllegalArgumentException("Label must be G_2xx or G_4xx") + } + + } + + override fun estimateAccuracy(endpoint: Endpoint): Double { + return this.performance.accuracy() } private fun logLikelihood(x: List, stats: Density): Double { diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt index 2baa3e9e48..198f21499f 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt @@ -8,7 +8,7 @@ import kotlin.math.exp /** * An online binary classifier for REST API actions using a Generalized Linear Model (logistic regression). * - * This model classifies between HTTP status codes 200 and 400, and updates its weights incrementally. + * This model classifies between HTTP status codes 200 and 400, and updates its weight incrementally. * It uses stochastic gradient descent (SGD) to learn the parameters. * * Assumes binary labels: @@ -17,29 +17,27 @@ import kotlin.math.exp * * @param dimension the number of features (from input encoding) * @param learningRate learning rate for SGD updates + * @param warmup the number of warmup updates to familiarize the classifier with at least a few true observations */ class GLMOnlineClassifier( private val learningRate: Double = 0.01 ) : AIModel { - private var dimension: Int? = null - private var weights: MutableList? = null - private var bias: Double = 0.0 - - // classifier state - private var cp: Int = 0 // correct predictions - private var tot: Int = 1 // total requests - private var ac: Double = 0.0 // accuracy ratio - - /** Must be called once to initialize model weights based on dimension */ - fun setDimension(d: Int) { - require(d > 0) { "Dimension must be positive." } - dimension = d - weights = MutableList(d) { 0.0 } - bias = 0.0 - this.cp = 0 - this.tot = 0 - this.ac = 0.0 + var warmup: Int = 10 + var dimension: Int? = null + var weights: MutableList? = null + var bias: Double = 0.0 + var performance: ClassifierPerformance = ClassifierPerformance(0, 1) + + /** Must be called once to initialize the model properties */ + fun setup(dimension: Int, warmup: Int) { + require(dimension > 0) { "Dimension must be positive." } + this.dimension = dimension + this.weights = MutableList(dimension) { 0.0 } + this.bias = 0.0 + require(warmup > 0 ) { "Warmup must be positive." } + this.warmup = warmup + this.performance = ClassifierPerformance(0, 1) } fun getModelParams(): List { @@ -47,29 +45,24 @@ class GLMOnlineClassifier( return weights!!.toList() + bias } - fun getDimension(): Int { - check(this.dimension != null) { "Classifier not initialized. Call setDimension first." } - return this.dimension!! + fun updatePerformance(predictionIsCorrect: Boolean) { + val totalCorrectPredictions = if (predictionIsCorrect) performance.correctPrediction + 1 else performance.correctPrediction + val totalSentRequests = performance.totalSentRequests + 1 + this.performance = ClassifierPerformance(totalCorrectPredictions, totalSentRequests) } - fun setCp(cp: Int) { - this.cp = cp - } - fun setTot(tot: Int){ - this.tot = tot - } + override fun classify(input: RestCallAction): AIResponseClassification { - fun getCorrectPredictions(): Int = cp - fun getTotalRequests(): Int = tot - fun getAccuracy(): Double = if (tot == 0) 0.0 else cp.toDouble() / tot + if (performance.totalSentRequests< warmup) { + throw IllegalStateException("Classifier not ready as warmup is not completed.") + } - override fun classify(input: RestCallAction): AIResponseClassification { - val x = InputEncoderUtils.encode(input).normalizedEncodedFeatures + val inputVector = InputEncoderUtils.encode(input).normalizedEncodedFeatures val dim = dimension ?: throw IllegalStateException("Dimension not set. Call setDimension() first.") - if (x.size != dim) throw IllegalArgumentException("Expected input vector of size $dim but got ${x.size}") + if (inputVector.size != dim) throw IllegalArgumentException("Expected input vector of size $dim but got ${inputVector.size}") - val z = x.zip(weights!!) { xi, wi -> xi * wi }.sum() + bias + val z = inputVector.zip(weights!!) { xi, wi -> xi * wi }.sum() + bias val prob200 = sigmoid(z) val prob400 = 1.0 - prob200 @@ -82,32 +75,42 @@ class GLMOnlineClassifier( } override fun estimateAccuracy(endpoint: Endpoint): Double { - // Strict accuracy - //TODO this accuracy can be dynamic for example based on the last 100 requests - if (this.tot == 0) { - return 0.0 - } - return this.cp.toDouble() / this.tot + return this.performance.accuracy() } override fun updateModel(input: RestCallAction, output: RestCallResult) { - val x = InputEncoderUtils.encode(input).normalizedEncodedFeatures + val inputVector = InputEncoderUtils.encode(input).normalizedEncodedFeatures - val dim = dimension ?: throw IllegalStateException("Dimension not set. Call setDimension() first.") - if (x.size != dim) throw IllegalArgumentException("Expected input vector of size $dim but got ${x.size}") + if (inputVector.size != this.dimension) { + throw IllegalArgumentException("Expected input vector of size ${this.dimension} but got ${inputVector.size}") + } - val y = when (output.getStatusCode()) { + /** + * Updating classifier performance based on its prediction + * The performance getting update only after the warmup procedure + */ + val trueStatusCode = output.getStatusCode() + if (this.performance.totalSentRequests <= this.warmup) { + updatePerformance(predictionIsCorrect = false) + }else{ + val predicted = classify(input).prediction() + updatePerformance(predictionIsCorrect = (predicted == trueStatusCode)) + } + + /** + * Updating model parameters + */ + val y = when (trueStatusCode) { 200 -> 1.0 400 -> 0.0 else -> throw IllegalArgumentException("Unsupported label: only 200 and 400 are handled") } - - val z = x.zip(weights!!) { xi, wi -> xi * wi }.sum() + bias + val z = inputVector.zip(weights!!) { xi, wi -> xi * wi }.sum() + bias val prediction = sigmoid(z) val error = prediction - y - for (i in x.indices) { - weights!![i] -= learningRate * error * x[i] + for (i in inputVector.indices) { + weights!![i] -= learningRate * error * inputVector[i] } bias -= learningRate * error } diff --git a/core/src/test/kotlin/org/evomaster/core/output/TestSuiteOrganizerTest.kt b/core/src/test/kotlin/org/evomaster/core/output/TestSuiteOrganizerTest.kt index e69de29bb2..55075ba0e6 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/TestSuiteOrganizerTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/TestSuiteOrganizerTest.kt @@ -0,0 +1,239 @@ +package org.evomaster.core.output + +import org.evomaster.core.TestUtils +import org.evomaster.core.output.naming.NumberedTestCaseNamingStrategy +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getEvaluatedIndividualWith +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getRestCallAction +import org.evomaster.core.output.sorting.SortingStrategy +import org.evomaster.core.problem.api.param.Param +import org.evomaster.core.problem.enterprise.EnterpriseActionGroup +import org.evomaster.core.problem.enterprise.SampleType +import org.evomaster.core.problem.graphql.GQMethodType +import org.evomaster.core.problem.graphql.GraphQLAction +import org.evomaster.core.problem.graphql.GraphQLIndividual +import org.evomaster.core.problem.graphql.GraphQlCallResult +import org.evomaster.core.problem.graphql.param.GQInputParam +import org.evomaster.core.problem.rest.data.HttpVerb +import org.evomaster.core.problem.rpc.RPCCallAction +import org.evomaster.core.problem.rpc.RPCIndividual +import org.evomaster.core.problem.rpc.param.RPCParam +import org.evomaster.core.search.EvaluatedIndividual +import org.evomaster.core.search.FitnessValue +import org.evomaster.core.search.Solution +import org.evomaster.core.search.gene.wrapper.OptionalGene +import org.evomaster.core.search.gene.string.StringGene +import org.junit.Test +import org.junit.jupiter.api.Assertions.assertEquals +import java.util.UUID + +class TestSuiteOrganizerTest { + + companion object { + val sortingStrategy = SortingStrategy.TARGET_INCREMENTAL + } + + @Test + fun restSortedByPathSegmentFirst() { + val noPathSegmentInd = getEvaluatedIndividualWith(getRestCallAction("/")) + val onePathSegmentInd = getEvaluatedIndividualWith(getRestCallAction("/organization")) + val twoPathSegmentsInd = getEvaluatedIndividualWith(getRestCallAction("/organization/{name}")) + val individuals = mutableListOf(noPathSegmentInd, onePathSegmentInd, twoPathSegmentsInd) + individuals.shuffle() + val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) + + assertEquals(sortedTestCases[0].test, noPathSegmentInd) + assertEquals(sortedTestCases[1].test, onePathSegmentInd) + assertEquals(sortedTestCases[2].test, twoPathSegmentsInd) + } + + @Test + fun restSortedByStatusCodeWhenEqualPathSegmentSize() { + val status200Ind = getEvaluatedIndividualWith(getRestCallAction("/organization"), 200) + val status401Ind = getEvaluatedIndividualWith(getRestCallAction("/organization"), 401) + val status500Ind = getEvaluatedIndividualWith(getRestCallAction("/organization"), 500) + val individuals = mutableListOf(status200Ind, status401Ind, status500Ind) + individuals.shuffle() + val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) + + assertEquals(sortedTestCases[0].test, status500Ind) + assertEquals(sortedTestCases[1].test, status200Ind) + assertEquals(sortedTestCases[2].test, status401Ind) + } + + @Test + fun restSortedByMethodWhenEqualPathSegmentsAndStatusCode() { + val getInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.GET)) + val postInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.POST)) + val putInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.PUT)) + val deleteInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.DELETE)) + val optionsInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.OPTIONS)) + val patchInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.PATCH)) + val traceInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.TRACE)) + val headInd = getEvaluatedIndividualWith(getRestCallAction("/organization", HttpVerb.HEAD)) + val individuals = mutableListOf(getInd, postInd, putInd, deleteInd, optionsInd, patchInd, traceInd, headInd) + individuals.shuffle() + val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) + + assertEquals(sortedTestCases[0].test, getInd) + assertEquals(sortedTestCases[1].test, postInd) + assertEquals(sortedTestCases[2].test, putInd) + assertEquals(sortedTestCases[3].test, deleteInd) + assertEquals(sortedTestCases[4].test, optionsInd) + assertEquals(sortedTestCases[5].test, patchInd) + assertEquals(sortedTestCases[6].test, traceInd) + assertEquals(sortedTestCases[7].test, headInd) + } + + @Test + fun graphSortedByMethodNameFirst() { + val aLetterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "aLetterMethod") + val bLetterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "bLetterMethod") + val cLetterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "cLetterMethod") + val individuals = mutableListOf(aLetterIndividual, bLetterIndividual, cLetterIndividual) + individuals.shuffle() + val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) + + assertEquals(sortedTestCases[0].test, aLetterIndividual) + assertEquals(sortedTestCases[1].test, bLetterIndividual) + assertEquals(sortedTestCases[2].test, cLetterIndividual) + } + + @Test + fun graphSortedByMethodTypeWhenEqualMethodNameAndParametersSize() { + val paramLambda = { name: String, value: String -> getGraphQLParam(name, value) } + val queryOneParameterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(1, paramLambda)) + val queryTwoParametersIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(2, paramLambda)) + val mutationOneParameterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.MUTATION, "myMethod", getListOfParams(1, paramLambda)) + val mutationTwoParametersIndividual = getGraphQLEvaluatedIndividual(GQMethodType.MUTATION, "myMethod", getListOfParams(2, paramLambda)) + val individuals = mutableListOf(queryOneParameterIndividual, queryTwoParametersIndividual, mutationOneParameterIndividual, mutationTwoParametersIndividual) + individuals.shuffle() + val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) + + assertEquals(sortedTestCases[0].test, queryOneParameterIndividual) + assertEquals(sortedTestCases[1].test, queryTwoParametersIndividual) + assertEquals(sortedTestCases[2].test, mutationOneParameterIndividual) + assertEquals(sortedTestCases[3].test, mutationTwoParametersIndividual) + } + + @Test + fun graphSortedByAmountOfParametersWhenEqualMethodNameAndType() { + val paramLambda = { name: String, value: String -> getGraphQLParam(name, value) } + val oneParameterIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(1, paramLambda)) + val twoParametersIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(2, paramLambda)) + val threeParametersIndividual = getGraphQLEvaluatedIndividual(GQMethodType.QUERY, "myMethod", getListOfParams(3, paramLambda)) + val individuals = mutableListOf(oneParameterIndividual, twoParametersIndividual, threeParametersIndividual) + individuals.shuffle() + val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) + + assertEquals(sortedTestCases[0].test, oneParameterIndividual) + assertEquals(sortedTestCases[1].test, twoParametersIndividual) + assertEquals(sortedTestCases[2].test, threeParametersIndividual) + } + + @Test + fun rpcSortedByClassNameFirst() { + val aFakeClassIndividual = getRPCEvaluatedIndividual("aFakeInterfaceClass:fakeInterfaceMethod") + val bFakeClassIndividual = getRPCEvaluatedIndividual("bFakeInterfaceClass:fakeInterfaceMethod") + val cFakeClassIndividual = getRPCEvaluatedIndividual("cFakeInterfaceClass:fakeInterfaceMethod") + val individuals = mutableListOf(aFakeClassIndividual, bFakeClassIndividual, cFakeClassIndividual) + individuals.shuffle() + val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) + + assertEquals(sortedTestCases[0].test, aFakeClassIndividual) + assertEquals(sortedTestCases[1].test, bFakeClassIndividual) + assertEquals(sortedTestCases[2].test, cFakeClassIndividual) + } + + @Test + fun rpcSortedByMethodNameWhenEqualClassName() { + val aFakeMethodIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:aFakeInterfaceMethod") + val bFakeMethodIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:bFakeInterfaceMethod") + val cFakeMethodIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:cFakeInterfaceMethod") + val individuals = mutableListOf(aFakeMethodIndividual, bFakeMethodIndividual, cFakeMethodIndividual) + individuals.shuffle() + val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) + + assertEquals(sortedTestCases[0].test, aFakeMethodIndividual) + assertEquals(sortedTestCases[1].test, bFakeMethodIndividual) + assertEquals(sortedTestCases[2].test, cFakeMethodIndividual) + } + + @Test + fun rpcSortedByAmountOfParametersWhenClassAndMethodNames() { + val paramLambda = { name: String, value: String -> getRPCParam(name, value) } + val oneParameterIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:fakeInterfaceMethod", getListOfParams(1, paramLambda)) + val twoParametersIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:fakeInterfaceMethod", getListOfParams(2, paramLambda)) + val threeParametersIndividual = getRPCEvaluatedIndividual("fakeInterfaceClass:fakeInterfaceMethod", getListOfParams(3, paramLambda)) + val individuals = mutableListOf(oneParameterIndividual, twoParametersIndividual, threeParametersIndividual) + individuals.shuffle() + val solution = Solution(individuals, "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val sortedTestCases = SortingHelper().sort(solution, NumberedTestCaseNamingStrategy(solution), sortingStrategy) + + assertEquals(sortedTestCases[0].test, oneParameterIndividual) + assertEquals(sortedTestCases[1].test, twoParametersIndividual) + assertEquals(sortedTestCases[2].test, threeParametersIndividual) + } + + private fun getGraphQLEvaluatedIndividual(query: GQMethodType, methodName: String, params: MutableList = mutableListOf()): EvaluatedIndividual { + val action = GraphQLAction(methodName, methodName, query, params) + + val actions = mutableListOf>() + actions.add(EnterpriseActionGroup(mutableListOf(action), GraphQLAction::class.java)) + + val individual = GraphQLIndividual(SampleType.RANDOM, actions) + TestUtils.doInitializeIndividualForTesting(individual) + + val results = listOf(GraphQlCallResult(action.getLocalId())) + return EvaluatedIndividual(FitnessValue(0.0), individual, results) + } + + private fun getListOfParams(amount: Int, paramFunction: (name: String, value: String) -> Param): MutableList { + val params = mutableListOf() + for (i in 0..amount) { + val name = UUID.randomUUID().toString() + val value = UUID.randomUUID().toString() + params.add(paramFunction(name, value)) + } + return params + } + + private fun getGraphQLParam(name: String, value: String): GQInputParam { + val op = OptionalGene(name, StringGene(name, value)) + return GQInputParam(name, op) + } + + private fun getRPCEvaluatedIndividual(interfaceId: String, params: MutableList = mutableListOf()): EvaluatedIndividual { + val action = RPCCallAction(interfaceId, "${interfaceId}_0", params, null, null) + val externalAction = EvaluatedIndividualBuilder.buildFakeDbExternalServiceAction(1).plus(EvaluatedIndividualBuilder.buildFakeRPCExternalServiceAction(1)) + + val individual = RPCIndividual(SampleType.RANDOM, actions=mutableListOf(action), externalServicesActions = mutableListOf(externalAction)) + TestUtils.doInitializeIndividualForTesting(individual) + + val results = listOf(GraphQlCallResult(action.getLocalId())) + return EvaluatedIndividual(FitnessValue(0.0), individual, results) + } + + private fun getRPCParam(name: String, value: String): RPCParam { + val op = OptionalGene(name, StringGene(name, value)) + return RPCParam(name, op) + } + + +} \ No newline at end of file From ebc1883ae176e9110268cb1b2b4269e15dd4bf6e Mon Sep 17 00:00:00 2001 From: Mohsen Taheri Shalmani Date: Fri, 29 Aug 2025 16:14:30 +0200 Subject: [PATCH 6/7] Update the classifier performance --- .../problem/rest/classifier/GaussianOnlineClassifier.kt | 7 ++++--- .../core/problem/rest/classifier/GeneralizedLinearModel.kt | 7 +++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt index 9482a554d1..fba9cebf5b 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt @@ -6,6 +6,8 @@ import org.evomaster.core.problem.rest.data.RestCallResult import kotlin.math.ln import kotlin.math.PI import kotlin.math.exp +import org.evomaster.core.search.service.Randomness +import kotlin.random.Random /** * Gaussian classifier for REST API calls. @@ -47,7 +49,6 @@ class GaussianOnlineClassifier : AIModel { this.density400 = Density(dimension) require(warmup > 0 ) { "Warmup must be positive." } this.warmup = warmup - this.performance = ClassifierPerformance(0, 1) } fun updatePerformance(predictionIsCorrect: Boolean) { @@ -98,11 +99,11 @@ class GaussianOnlineClassifier : AIModel { /** * Updating classifier performance based on its prediction - * The performance getting update only after the warmup procedure + * Before the warmup is completed, the update is based on a crude guess (like a coin flip). */ val trueStatusCode = output.getStatusCode() if (this.performance.totalSentRequests <= this.warmup) { - updatePerformance(predictionIsCorrect = false) + updatePerformance(predictionIsCorrect = Random.nextBoolean()) }else{ val predicted = classify(input).prediction() updatePerformance(predictionIsCorrect = (predicted == trueStatusCode)) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt index 198f21499f..d5fdd757ae 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt @@ -4,6 +4,7 @@ import org.evomaster.core.problem.rest.data.Endpoint import org.evomaster.core.problem.rest.data.RestCallAction import org.evomaster.core.problem.rest.data.RestCallResult import kotlin.math.exp +import kotlin.random.Random /** * An online binary classifier for REST API actions using a Generalized Linear Model (logistic regression). @@ -34,10 +35,8 @@ class GLMOnlineClassifier( require(dimension > 0) { "Dimension must be positive." } this.dimension = dimension this.weights = MutableList(dimension) { 0.0 } - this.bias = 0.0 require(warmup > 0 ) { "Warmup must be positive." } this.warmup = warmup - this.performance = ClassifierPerformance(0, 1) } fun getModelParams(): List { @@ -87,11 +86,11 @@ class GLMOnlineClassifier( /** * Updating classifier performance based on its prediction - * The performance getting update only after the warmup procedure + * Before the warmup is completed, the update is based on a crude guess (like a coin flip). */ val trueStatusCode = output.getStatusCode() if (this.performance.totalSentRequests <= this.warmup) { - updatePerformance(predictionIsCorrect = false) + updatePerformance(predictionIsCorrect = Random.nextBoolean()) }else{ val predicted = classify(input).prediction() updatePerformance(predictionIsCorrect = (predicted == trueStatusCode)) From 14ec4df7108a0e3d9bc2d85a0faf6663b387f9dc Mon Sep 17 00:00:00 2001 From: Mohsen Taheri Shalmani Date: Fri, 29 Aug 2025 16:34:52 +0200 Subject: [PATCH 7/7] Cleanup classifier performance --- .../rest/classifier/ClassifierPerformance.kt | 12 ++++++++++++ .../rest/classifier/GaussianOnlineClassifier.kt | 17 +++++------------ .../rest/classifier/GeneralizedLinearModel.kt | 14 ++++---------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/ClassifierPerformance.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/ClassifierPerformance.kt index 70819cff27..b91ef2947d 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/ClassifierPerformance.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/ClassifierPerformance.kt @@ -22,4 +22,16 @@ class ClassifierPerformance( 0.0 } } + + /** + * Returns a new ClassifierPerformance with updated counts + * based on whether the latest prediction was correct. + */ + fun updatePerformance(predictionIsCorrect: Boolean): ClassifierPerformance { + val totalCorrectPredictions = + if (predictionIsCorrect) correctPrediction + 1 else correctPrediction + val totalSentRequests = totalSentRequests + 1 + return ClassifierPerformance(totalCorrectPredictions, totalSentRequests) + } + } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt index fba9cebf5b..fd7219afd5 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GaussianOnlineClassifier.kt @@ -6,7 +6,6 @@ import org.evomaster.core.problem.rest.data.RestCallResult import kotlin.math.ln import kotlin.math.PI import kotlin.math.exp -import org.evomaster.core.search.service.Randomness import kotlin.random.Random /** @@ -44,19 +43,13 @@ class GaussianOnlineClassifier : AIModel { /** Must be called once to initialize the model properties */ fun setup(dimension: Int, warmup: Int) { require(dimension > 0 ) { "Dimension must be positive." } + require(warmup > 0 ) { "Warmup must be positive." } this.dimension = dimension this.density200 = Density(dimension) this.density400 = Density(dimension) - require(warmup > 0 ) { "Warmup must be positive." } this.warmup = warmup } - fun updatePerformance(predictionIsCorrect: Boolean) { - val totalCorrectPredictions = if (predictionIsCorrect) performance.correctPrediction + 1 else performance.correctPrediction - val totalSentRequests = performance.totalSentRequests + 1 - this.performance = ClassifierPerformance(totalCorrectPredictions, totalSentRequests) - } - override fun classify(input: RestCallAction): AIResponseClassification { @@ -102,11 +95,11 @@ class GaussianOnlineClassifier : AIModel { * Before the warmup is completed, the update is based on a crude guess (like a coin flip). */ val trueStatusCode = output.getStatusCode() - if (this.performance.totalSentRequests <= this.warmup) { - updatePerformance(predictionIsCorrect = Random.nextBoolean()) - }else{ + performance = if (performance.totalSentRequests < warmup) { + performance.updatePerformance(Random.nextBoolean()) + } else { val predicted = classify(input).prediction() - updatePerformance(predictionIsCorrect = (predicted == trueStatusCode)) + performance.updatePerformance(predicted == trueStatusCode) } /** diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt index d5fdd757ae..b331eb631a 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/GeneralizedLinearModel.kt @@ -44,12 +44,6 @@ class GLMOnlineClassifier( return weights!!.toList() + bias } - fun updatePerformance(predictionIsCorrect: Boolean) { - val totalCorrectPredictions = if (predictionIsCorrect) performance.correctPrediction + 1 else performance.correctPrediction - val totalSentRequests = performance.totalSentRequests + 1 - this.performance = ClassifierPerformance(totalCorrectPredictions, totalSentRequests) - } - override fun classify(input: RestCallAction): AIResponseClassification { if (performance.totalSentRequests< warmup) { @@ -89,11 +83,11 @@ class GLMOnlineClassifier( * Before the warmup is completed, the update is based on a crude guess (like a coin flip). */ val trueStatusCode = output.getStatusCode() - if (this.performance.totalSentRequests <= this.warmup) { - updatePerformance(predictionIsCorrect = Random.nextBoolean()) - }else{ + performance = if (performance.totalSentRequests < warmup) { + performance.updatePerformance(Random.nextBoolean()) + } else { val predicted = classify(input).prediction() - updatePerformance(predictionIsCorrect = (predicted == trueStatusCode)) + performance.updatePerformance(predicted == trueStatusCode) } /**