@specs-feup/kadabra
Version:
A Java source-to-source compiler written in Typescript
238 lines • 7.58 kB
JavaScript
import { primitive2Class } from "../Utils.js";
/**
* Class defining the structure of an autotuner
*/
export class Configs {
///////////////////////////////////////////////////
//////////////// USEFUL CONSTANTS /////////////////
///////////////////////////////////////////////////
static PACKAGE = "autotuner.configs.";
static FACTORY = Configs.PACKAGE + "autotuner.configs.";
static RANGED = Configs.PACKAGE + "knobs.number.ranged.";
static Tuple = "tdrc.tuple.Tuple";
static order = {
normal: Configs.FACTORY + "::normal",
random: Configs.FACTORY + "::random",
};
/**
A list of values to test in the order they are given.
**/
static default(knobs, values, type) {
return list2Config(knobs, "normal", values, false, type);
}
/**
A list of values to test in random order.
**/
static random(knobs, values, type) {
return list2Config(knobs, "random", values, false, type);
}
static combine(knobs, values, type) {
if (!Array.isArray(values) || values.length < 2) {
throw new Error("At least two values must be provided to combine values");
}
const args = values.map((arg) => {
return "java.util.Arrays.asList(" + arg.join(",") + ")";
});
return new Configuration(knobs, Configs.FACTORY +
".normal(tdrc.utils.ListUtils.createTuplesFromList(" +
args.join(",") +
"))", type);
}
/*
This configuration uses Ranged knobs, which are defined in the lower part of this file (e.g. IntegerRange)
*/
static randomOf(knobs, ranges) {
return rangedConfig(knobs, ranges, "random", true);
}
static range(knobs, ranges) {
return rangedConfig(knobs, ranges, "range", true);
}
static around(knobs, ranges) {
return rangedConfig(knobs, ranges, "around", true);
}
static linear(knobs, ranges) {
return rangedConfig(knobs, ranges, "linear", true);
}
static custom(knobs, configCode, type) {
return new Configuration(knobs, configCode, type);
}
}
export class Configuration {
applier;
configCode;
type;
constructor(knobs, configCode, type) {
if (Array.isArray(knobs)) {
let applierCode = "(knobs) -> {\n";
for (let i = 0; i < knobs.length; i++) {
const k = knobs[i];
applierCode +=
"\t" +
k.staticAccess +
" = (" +
k.type +
")knobs.get(" +
i +
");\n";
}
this.applier = applierCode + "}";
}
else {
this.applier = `(knob)-> ${knobs.staticAccess} = knob`;
}
this.type = type;
this.configCode = configCode;
}
declare(name) {
return (Configs.PACKAGE +
"Configuration<" +
this.type +
"> " +
name +
" = " +
this.get());
}
declareProvider(name) {
return ("java.util.function.Supplier< " +
Configs.PACKAGE +
"Configuration<" +
this.type +
">> " +
name +
" = " +
this.provider());
}
provider() {
return "()-> " + this.configCode;
}
get() {
return this.configCode;
}
toString() {
return this.get();
}
}
//////////////////////////////////////////////////////////////
//////////////// GENERIC CONFIGS USING LISTS /////////////////
//////////////////////////////////////////////////////////////
function list2Config(knobs, constructor, values, acceptsSingle, type) {
if (values.length == 0) {
throw new Error("At least one value must be provided to create a " +
constructor +
" configuration");
}
if (values.length == 1 && acceptsSingle) {
return new Configuration(knobs, Configs.FACTORY + "." + constructor + "(" + values.join(",") + ")", type);
}
return new Configuration(knobs, Configs.FACTORY + "." + constructor + "(" + values.join(",") + ")", type);
}
///////////////////////////////////////////////////////
//////////////// CONFIGS USING RANGES /////////////////
///////////////////////////////////////////////////////
export function rangedConfig(knobs, ranges, type, acceptsSingle) {
let args;
if (Array.isArray(ranges)) {
if (ranges.length == 0) {
throw new Error("At least one value must be provided to create a(n) " +
type +
" configuration");
}
args = ranges.map(function (range) {
return range.instance();
});
}
else {
args = [ranges.instance()];
}
return list2Config(knobs, "", args, acceptsSingle, type);
}
/*
Ranged knob is used in the configurations, use this if you intend to create knobs containing multiple parameters (one RangedKnob per knob) and combine them in a configuration
*/
export class PrimitiveRange {
type;
lowerLimit;
upperLimit;
step;
value;
descend;
ascend;
constructor(type, lowerLimit, upperLimit, step = 1, value) {
this.type = primitive2Class(type);
this.lowerLimit = lowerLimit;
this.upperLimit = upperLimit;
this.step = step;
this.value = value;
this.descend = undefined;
this.ascend = undefined;
}
setClimbers(descend, ascend) {
this.descend = descend;
this.ascend = ascend;
this.step = undefined;
return this;
}
initValue(value) {
this.value = value;
return this;
}
toConfig() {
const instanceCode = this.instance();
return Configs.FACTORY + ".range(" + instanceCode + ")";
}
instance() {
if (this.ascend != undefined) {
let newKnob = "new " +
Configs.RANGED +
"CustomStep" +
this.type +
"Knob(" +
this.lowerLimit +
"," +
this.upperLimit +
",";
if (this.value !== undefined) {
newKnob += this.value + ",";
}
if (this.descend === undefined) {
throw new Error("Expected descend to be defined.");
}
return newKnob + this.descend + "," + this.ascend + ")";
}
let newKnob = "new " +
Configs.RANGED +
this.type +
"Step(" +
this.lowerLimit +
"," +
this.upperLimit +
",";
if (this.value !== undefined) {
newKnob += this.value + ",";
}
if (this.step === undefined) {
throw new Error("Expected step to be defined.");
}
return newKnob + this.step + ")";
}
declare(name) {
return (Configs.RANGED +
"RangedKnob<" +
this.type +
">" +
name +
" = " +
this.instance());
}
}
export class IntegerRange extends PrimitiveRange {
constructor(lowerLimit, upperLimit, step, value) {
super("Integer", lowerLimit, upperLimit, step, value);
}
}
export class FloatRange extends PrimitiveRange {
constructor(lowerLimit, upperLimit, step, value) {
super("Float", lowerLimit, upperLimit, step, value);
}
}
//# sourceMappingURL=Configs.js.map