Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion docs/export/minerva.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,13 @@ The generated firmware example intentionally contains placeholders. Confirm the

## Maintained JVM Sample

`sk.ainet.compile.minerva.examples.MinervaTinyMlpExportSample` builds a tiny two-layer MLP, reads Minerva paths from environment variables, invokes the export facade, and prints bundle and verification status. `MinervaTinyMlpExportSampleTest` validates the sample graph and NPZ generation without real device keys.
`sk.ainet.compile.minerva.examples.MinervaTinyMlpExportSample` builds a tiny two-layer MLP, reads Minerva paths from environment variables or Gradle properties, invokes the export facade, and prints bundle and verification status.

```bash
./gradlew :skainet-compile:skainet-compile-minerva:runMinervaTinyMlpSample
```

Without `MINERVA_COMPILER_SCRIPT`, the task runs a dry validation through compatibility, lowering, and in-memory NPZ generation. Add `-Pminerva.compilerScript`, `-Pminerva.runtimeRoot`, `-Pminerva.calibrationNpz`, and `-Pminerva.keyFile` to run the real compiler path. `MinervaTinyMlpExportSampleTest` validates the sample graph and NPZ generation without real device keys.

## Export Path Choice

Expand Down
15 changes: 14 additions & 1 deletion docs/modules/ROOT/pages/how-to/minerva-export.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,20 @@ Run the sample after configuring libminerva:
[source,bash]
----
./gradlew :skainet-compile:skainet-compile-minerva:jvmTest
./gradlew :skainet-compile:skainet-compile-minerva:jvmJar
./gradlew :skainet-compile:skainet-compile-minerva:runMinervaTinyMlpSample
----

Without `MINERVA_COMPILER_SCRIPT`, the sample task runs a dry validation through compatibility, lowering, and in-memory NPZ generation. Configure the runtime with Gradle properties or matching environment variables to run the real compiler and host verification:

[source,bash]
----
./gradlew :skainet-compile:skainet-compile-minerva:runMinervaTinyMlpSample \
-Pminerva.compilerScript="$MINERVA_COMPILER_SCRIPT" \
-Pminerva.runtimeRoot="$MINERVA_RUNTIME_ROOT" \
-Pminerva.calibrationNpz="$MINERVA_CALIBRATION_NPZ" \
-Pminerva.keyFile="$MINERVA_KEY_FILE" \
-Pminerva.hostVerification.runCmakeBuild=true \
-Pminerva.hostVerification.runCTest=true
----

The sample graph is covered by `MinervaTinyMlpExportSampleTest`, which validates compatibility, lowering, and NPZ generation without requiring real device keys.
Expand Down
43 changes: 43 additions & 0 deletions skainet-compile/skainet-compile-minerva/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ val minervaHostVerificationEnabled = providers.gradleProperty("minerva.hostVerif
.orElse(false)
val minervaRuntimeRoot = providers.gradleProperty("minerva.runtimeRoot")
val minervaCompilerScript = providers.gradleProperty("minerva.compilerScript")
val minervaKeyFile = providers.gradleProperty("minerva.keyFile")
val minervaCalibrationNpz = providers.gradleProperty("minerva.calibrationNpz")
val minervaRunCmakeBuild = providers.gradleProperty("minerva.hostVerification.runCmakeBuild")
val minervaRunCTest = providers.gradleProperty("minerva.hostVerification.runCTest")
val minervaHostOutputPath = providers.gradleProperty("minerva.hostVerification.hostOutputPath")

val jvmMainCompilation = kotlin.targets.getByName("jvm").compilations.getByName("main")

tasks.register("minervaHostVerification") {
group = "verification"
Expand All @@ -47,3 +54,39 @@ tasks.register("minervaHostVerification") {
inputs.property("minerva.runtimeRoot", minervaRuntimeRoot.orElse(""))
inputs.property("minerva.compilerScript", minervaCompilerScript.orElse(""))
}

tasks.register<JavaExec>("runMinervaTinyMlpSample") {
group = "application"
description = "Runs the maintained Minerva tiny MLP export sample."

dependsOn(tasks.named("jvmJar"))

mainClass.set("sk.ainet.compile.minerva.examples.MinervaTinyMlpExportSample")

classpath = files(
jvmMainCompilation.runtimeDependencyFiles,
tasks.named("jvmJar").get().outputs.files
)

minervaCompilerScript.orElse(providers.environmentVariable("MINERVA_COMPILER_SCRIPT")).orNull?.let {
environment("MINERVA_COMPILER_SCRIPT", it)
}
minervaRuntimeRoot.orElse(providers.environmentVariable("MINERVA_RUNTIME_ROOT")).orNull?.let {
environment("MINERVA_RUNTIME_ROOT", it)
}
minervaKeyFile.orElse(providers.environmentVariable("MINERVA_KEY_FILE")).orNull?.let {
environment("MINERVA_KEY_FILE", it)
}
minervaCalibrationNpz.orElse(providers.environmentVariable("MINERVA_CALIBRATION_NPZ")).orNull?.let {
environment("MINERVA_CALIBRATION_NPZ", it)
}
minervaRunCmakeBuild.orElse(providers.environmentVariable("MINERVA_RUN_CMAKE")).orNull?.let {
environment("MINERVA_RUN_CMAKE", it)
}
minervaRunCTest.orElse(providers.environmentVariable("MINERVA_RUN_CTEST")).orNull?.let {
environment("MINERVA_RUN_CTEST", it)
}
minervaHostOutputPath.orElse(providers.environmentVariable("MINERVA_HOST_OUTPUT_PATH")).orNull?.let {
environment("MINERVA_HOST_OUTPUT_PATH", it)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sk.ainet.compile.minerva.examples

import sk.ainet.compile.minerva.MinervaExportFacade
import sk.ainet.compile.minerva.MinervaExportFailureKind
import sk.ainet.compile.minerva.MinervaExportOptions
import sk.ainet.compile.minerva.MinervaHostVerificationMetadata
import sk.ainet.lang.graph.DefaultComputeGraph
Expand All @@ -20,12 +21,11 @@ import sk.ainet.lang.types.DType
internal object MinervaTinyMlpExportSample {

@JvmStatic
internal fun main(args: Array<String>): Unit {
public fun main(args: Array<String>): Unit {
val env = System.getenv()
val compilerScript = envPath(env, "MINERVA_COMPILER_SCRIPT")
if (compilerScript == null) {
println("Set MINERVA_COMPILER_SCRIPT to run the Minerva tiny MLP export sample.")
return
println("MINERVA_COMPILER_SCRIPT is not set; running dry validation through NPZ generation.")
}

val options = exportOptions(
Expand All @@ -47,6 +47,10 @@ internal object MinervaTinyMlpExportSample {
result.hostVerification?.let { verification ->
println("Host verification: ${verification.status}")
}
if (compilerScript == null && result.failure?.kind == MinervaExportFailureKind.COMPILER_PREREQUISITE_FAILED) {
println("Dry validation completed: graph is compatible and model.npz was generated in memory.")
return
}
if (result.failed) {
error(result.failure?.message ?: "Minerva export failed.")
}
Expand Down Expand Up @@ -114,7 +118,7 @@ internal object MinervaTinyMlpExportSample {
internal fun exportOptions(
outputDir: String = "build/minerva",
projectName: String = "TinySecureMlp",
compilerScript: String,
compilerScript: String? = null,
runtimeRoot: String? = null,
keyFile: String? = null,
calibrationNpz: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class MinervaTinyMlpExportSampleTest {
assertTrue(report.compatible, report.issues.joinToString { it.message })
assertEquals(2, report.layerCount)

val result = MinervaExportFacade().exportGraph(graph, options.copy(compilerScript = null))
val dryRunOptions = MinervaTinyMlpExportSample.exportOptions()
val result = MinervaExportFacade().exportGraph(graph, dryRunOptions)

assertEquals(GraphExportStatus.FAILED, result.status)
assertEquals(MinervaExportFailureKind.COMPILER_PREREQUISITE_FAILED, result.failure?.kind)
Expand Down
Loading