Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5b8dd57
feat(workflow-compiling-service): export a workflow as a standalone P…
kz930 Sep 1, 2026
a7558eb
test(workflow-compiling-service): run an operator both ways and compa…
kz930 Sep 1, 2026
cba725f
test(workflow-compiling-service): verify a generated script against t…
kz930 Sep 1, 2026
bc8fc17
ci: give the verify spec a job with an interpreter, and keep it out o…
kz930 Sep 2, 2026
c819d33
docs(verify): say what "unset" actually means for an optional knob
kz930 Sep 2, 2026
bd79451
Merge remote-tracking branch 'upstream/main' into feat/standalone-ml-…
kz930 Sep 2, 2026
009b5e4
feat(operator): export the machine-learning operators as Python
kz930 Sep 2, 2026
5438523
test(verify): assert the tiers this batch actually changes
kz930 Sep 2, 2026
6c1c60a
chore: leave the harness to the change that introduces it
kz930 Sep 2, 2026
b70ee21
Merge upstream/main
kz930 Sep 2, 2026
c538deb
chore: leave the verification rows to the harness change
kz930 Sep 2, 2026
e8fc4e5
chore: move the scorer and the estimators into their own changes
kz930 Sep 2, 2026
42510f5
docs: say the thing once
kz930 Sep 2, 2026
11ac8f9
chore: follow the SVR constant to the name it now carries
kz930 Sep 3, 2026
72b1779
test(verify): follow the fixture columns to their new names
kz930 Sep 9, 2026
f7994b6
Merge upstream/main into feat/standalone-ml-operators
kz930 Sep 10, 2026
4583633
Merge branch 'main' into feat/standalone-ml-operators
kz930 Sep 18, 2026
e405791
Merge branch 'main' into feat/standalone-ml-operators
kz930 Sep 18, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,35 @@
import org.apache.texera.amber.operator.machineLearning.sklearnAdvanced.base.ParamClass;

public enum SklearnAdvancedKNNParameters implements ParamClass {
n_neighbors("n_neighbors", "int"),
p("p", "int"),
weights("weights", "str"),
algorithm("algorithm", "str"),
leaf_size("leaf_size", "int"),
// A metric is named, not measured: "minkowski" and the rest of the accepted
// set are words, so int() rejects every value scikit-learn would take.
metric("metric", "str"),
// Bounds are scikit-learn's own: a neighbour count and a leaf size start at one, and the
// Minkowski power is open at zero.
n_neighbors("n_neighbors", "int", "5") { @Override public String getMinimum() { return ">=1"; } },
p("p", "int", "2") { @Override public String getMinimum() { return ">0"; } },
weights("weights", "str", "", "uniform", "distance"),
algorithm("algorithm", "str", "", "auto", "ball_tree", "kd_tree", "brute"),
leaf_size("leaf_size", "int", "30") { @Override public String getMinimum() { return ">=1"; } },
// A metric is named, not measured: "minkowski" and the rest are words, so the
// int() this used to declare rejected every value scikit-learn would take. The
// set is the one every `algorithm` above accepts -- the tree algorithms take
// fewer metrics than brute force, and naming a brute-only metric here would
// break the moment the sibling knob is moved off `auto`.
metric("metric", "str", "minkowski", "minkowski", "euclidean", "manhattan",
"chebyshev", "cityblock", "l1", "l2"),
// The only one that is not a scalar. scikit-learn wants a mapping of extra
// keyword arguments for the metric, so the user's text is read as JSON.
metric_params("metric_params", "json.loads");
metric_params("metric_params", "json.loads", "{}");

private final String name;
private final String type;
private final String sampleValue;
private final String[] allowedValues;

SklearnAdvancedKNNParameters(String name, String type) {
SklearnAdvancedKNNParameters(
String name, String type, String sampleValue, String... allowedValues) {
this.name = name;
this.type = type;
this.sampleValue = sampleValue;
this.allowedValues = allowedValues;
}

public String getType() {
Expand All @@ -49,4 +60,12 @@ public String getType() {
public String getName() {
return this.name;
}

public String getSampleValue() {
return this.sampleValue;
}

public String[] getAllowedValues() {
return this.allowedValues.clone();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,41 @@
import org.apache.texera.amber.operator.machineLearning.sklearnAdvanced.base.ParamClass;

public enum SklearnAdvancedSVCParameters implements ParamClass {
C("C", "float"),
kernel("kernel", "str"),
gamma("gamma", "float"),
degree("degree", "int"),
coef0("coef0", "float"),
tol("tol", "float"),
probability("probability", "(lambda value: value.lower() == \"true\")");
// Bounds are scikit-learn's own, whose ranges are open at zero for the two below and
// closed for degree.
C("C", "float", "1.0") { @Override public String getMinimum() { return ">0"; } },
kernel("kernel", "str", "", "rbf", "linear", "poly", "sigmoid", "precomputed"),
// gamma takes either of two words or a number, so no converter of a name covers it, and
// the pattern states what this one takes. Digits are [0-9] rather than \d so the browser
// and Python read it alike. It lets a negative through for the estimator to refuse, since
// excluding the sign would also exclude -0.0, which the estimator takes.
gamma(
"gamma",
"(lambda value: value.strip() if value.strip() in (\"scale\", \"auto\") else float(value))",
"scale") {
@Override
public String getPattern() {
return "^\\s*(?:scale|auto|[-+]?(?:(?:[0-9]+(?:_[0-9]+)*)?\\.(?:[0-9]+(?:_[0-9]+)*)"
+ "|(?:[0-9]+(?:_[0-9]+)*)\\.?)(?:[eE][-+]?[0-9]+(?:_[0-9]+)*)?)\\s*$";
}
},
degree("degree", "int", "3") { @Override public String getMinimum() { return ">=0"; } },
// coef0 is the one parameter here with no bound at either end.
coef0("coef0", "float", "0.0"),
tol("tol", "float", "0.001") { @Override public String getMinimum() { return ">0"; } },
probability("probability", "(lambda value: value.lower() == \"true\")", "", "false", "true");

private final String name;
private final String type;
private final String sampleValue;
private final String[] allowedValues;

SklearnAdvancedSVCParameters(String name, String type) {
SklearnAdvancedSVCParameters(
String name, String type, String sampleValue, String... allowedValues) {
this.name = name;
this.type = type;
this.sampleValue = sampleValue;
this.allowedValues = allowedValues;
}

public String getType() {
Expand All @@ -45,4 +66,12 @@ public String getType() {
public String getName() {
return this.name;
}

public String getSampleValue() {
return this.sampleValue;
}

public String[] getAllowedValues() {
return this.allowedValues.clone();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,42 @@
import org.apache.texera.amber.operator.machineLearning.sklearnAdvanced.base.ParamClass;

public enum SklearnAdvancedSVRParameters implements ParamClass {
C("C", "float"),
kernel("kernel", "str"),
gamma("gamma", "float"),
degree("degree", "int"),
coef0("coef0", "float"),
tol("tol", "float"),
shrinking("shrinking", "(lambda value: value.lower() == \"true\")"),
verbose("verbose", "(lambda value: value.lower() == \"true\")"),
epsilon("epsilon", "float"),
cache_size("cache_size", "int"),
max_iter("max_iter", "int");
// Bounds are scikit-learn's own; see SVC for the shared ones.
C("C", "float", "1.0") { @Override public String getMinimum() { return ">0"; } },
kernel("kernel", "str", "", "rbf", "linear", "poly", "sigmoid", "precomputed"),
// Same converter and shape as SVC's gamma -- see there for why each is spelled this way.
gamma(
"gamma",
"(lambda value: value.strip() if value.strip() in (\"scale\", \"auto\") else float(value))",
"scale") {
@Override
public String getPattern() {
return "^\\s*(?:scale|auto|[-+]?(?:(?:[0-9]+(?:_[0-9]+)*)?\\.(?:[0-9]+(?:_[0-9]+)*)"
+ "|(?:[0-9]+(?:_[0-9]+)*)\\.?)(?:[eE][-+]?[0-9]+(?:_[0-9]+)*)?)\\s*$";
}
},
degree("degree", "int", "3") { @Override public String getMinimum() { return ">=0"; } },
coef0("coef0", "float", "0.0"),
tol("tol", "float", "0.001") { @Override public String getMinimum() { return ">0"; } },
shrinking("shrinking", "(lambda value: value.lower() == \"true\")", "", "true", "false"),
verbose("verbose", "(lambda value: value.lower() == \"true\")", "", "false", "true"),
epsilon("epsilon", "float", "0.1") { @Override public String getMinimum() { return ">=0"; } },
cache_size("cache_size", "int", "200") { @Override public String getMinimum() { return ">0"; } },
// -1 is SVR's own value for no iteration limit, which is also why the bound is -1 and not
// zero: the sentinel has to remain reachable.
max_iter("max_iter", "int", "-1") { @Override public String getMinimum() { return ">=-1"; } };

private final String name;
private final String type;
private final String sampleValue;
private final String[] allowedValues;

SklearnAdvancedSVRParameters(String name, String type) {
SklearnAdvancedSVRParameters(
String name, String type, String sampleValue, String... allowedValues) {
this.name = name;
this.type = type;
this.sampleValue = sampleValue;
this.allowedValues = allowedValues;
}

public String getType() {
Expand All @@ -49,4 +67,12 @@ public String getType() {
public String getName() {
return this.name;
}

public String getSampleValue() {
return this.sampleValue;
}

public String[] getAllowedValues() {
return this.allowedValues.clone();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,27 @@ import org.apache.texera.amber.operator.metadata.annotations.{
HideAnnotation
}

/**
* One row of a trainer's parameter table. `parametersSource` decides which of the two inputs
* the row uses, and the hide rules below show only that one, so exactly one of them is needed
* and neither can be required outright.
*/
@JsonSchemaInject(json = """
{
"allOf": [
{
"if": { "properties": { "parametersSource": { "const": true } } },
"then": { "required": ["attribute"] },
"else": { "required": ["value"] }
}
]
}
""")
class HyperParameters[T] {

// Two rows naming one parameter emit its keyword argument twice, which the generated
// Python will not compile, so the form warns on the row rather than letting it be added.
@JsonSchemaInject(json = """{ "uniqueAmongRows": true }""")
@JsonProperty(required = true)
@JsonSchemaTitle("Parameter")
@JsonPropertyDescription("Choose the name of the parameter")
Expand Down
Loading
Loading