This commit is contained in:
porink0424
2024-03-22 10:49:44 +09:00
parent 083946ce5c
commit ffc096263a
3 changed files with 354 additions and 350 deletions
+68 -68
View File
@@ -1,99 +1,99 @@
declare const IS_VSCODE: boolean
declare const IS_VSCODE: boolean;
type TrialState = "Running" | "Complete" | "Pruned" | "Fail" | "Waiting"
type TrialStateFinished = "Complete" | "Fail" | "Pruned"
type StudyDirection = "maximize" | "minimize" | "not_set"
type TrialState = "Running" | "Complete" | "Pruned" | "Fail" | "Waiting";
type TrialStateFinished = "Complete" | "Fail" | "Pruned";
type StudyDirection = "maximize" | "minimize" | "not_set";
type OptunaStorage = {
getStudies: () => Promise<StudySummary[]>
getStudy: (idx: number) => Promise<Study | null>
}
getStudies: () => Promise<StudySummary[]>;
getStudy: (idx: number) => Promise<Study | null>;
};
type FloatDistribution = {
type: "FloatDistribution"
low: number
high: number
step: number | null
log: boolean
}
type: "FloatDistribution";
low: number;
high: number;
step: number | null;
log: boolean;
};
type IntDistribution = {
type: "IntDistribution"
low: number
high: number
step: number | null
log: boolean
}
type: "IntDistribution";
low: number;
high: number;
step: number | null;
log: boolean;
};
type CategoricalChoiceType = null | boolean | number | string
type CategoricalChoiceType = null | boolean | number | string;
type CategoricalDistribution = {
type: "CategoricalDistribution"
choices: CategoricalChoiceType[]
}
type: "CategoricalDistribution";
choices: CategoricalChoiceType[];
};
type TrialIntermediateValue = {
step: number
value: number
}
step: number;
value: number;
};
type Distribution =
| FloatDistribution
| IntDistribution
| CategoricalDistribution
| CategoricalDistribution;
type Attribute = {
key: string
value: string
}
key: string;
value: string;
};
type AttributeSpec = {
key: string
sortable: boolean
}
key: string;
sortable: boolean;
};
type StudySummary = {
study_id: number
study_name: string
directions: StudyDirection[]
}
study_id: number;
study_name: string;
directions: StudyDirection[];
};
type Study = {
study_id: number
study_name: string
directions: StudyDirection[]
union_search_space: SearchSpaceItem[]
intersection_search_space: SearchSpaceItem[]
union_user_attrs: AttributeSpec[]
datetime_start?: Date
trials: Trial[]
}
study_id: number;
study_name: string;
directions: StudyDirection[];
union_search_space: SearchSpaceItem[];
intersection_search_space: SearchSpaceItem[];
union_user_attrs: AttributeSpec[];
datetime_start?: Date;
trials: Trial[];
};
type Trial = {
trial_id: number
number: number
study_id: number
state: TrialState
values?: number[]
params: TrialParam[]
intermediate_values: TrialIntermediateValue[]
user_attrs: Attribute[]
datetime_start?: Date
datetime_complete?: Date
}
trial_id: number;
number: number;
study_id: number;
state: TrialState;
values?: number[];
params: TrialParam[];
intermediate_values: TrialIntermediateValue[];
user_attrs: Attribute[];
datetime_start?: Date;
datetime_complete?: Date;
};
type TrialParam = {
name: string
param_internal_value: number
param_external_value: CategoricalChoiceType
param_external_type: string
distribution: Distribution
}
name: string;
param_internal_value: number;
param_external_value: CategoricalChoiceType;
param_external_type: string;
distribution: Distribution;
};
type SearchSpaceItem = {
name: string
}
name: string;
};
type ParamImportance = {
name: string
importance: number
}
name: string;
importance: number;
};
+142 -140
View File
@@ -1,4 +1,4 @@
import { SetterOrUpdater } from "recoil"
import { SetterOrUpdater } from "recoil";
// JournalStorage
enum JournalOperation {
@@ -15,92 +15,92 @@ enum JournalOperation {
}
interface JournalOpBase {
op_code: JournalOperation
workor_id: string
op_code: JournalOperation;
workor_id: string;
}
interface JournalOpCreateStudy extends JournalOpBase {
study_name: string
directions: number[] // TODO(gen740): introduce Study Direction enum
study_name: string;
directions: number[]; // TODO(gen740): introduce Study Direction enum
}
interface JournalOpDeleteStudy extends JournalOpBase {
study_id: number
study_id: number;
}
interface JournalOpCreateTrial extends JournalOpBase {
study_id: number
datetime_start?: string
datetime_complete?: string
distributions?: { [key: string]: string }
study_id: number;
datetime_start?: string;
datetime_complete?: string;
distributions?: { [key: string]: string };
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
params?: { [key: string]: any }
params?: { [key: string]: any };
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
user_attrs?: { [key: string]: any }
user_attrs?: { [key: string]: any };
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
system_attrs?: { [key: string]: any }
state?: number
intermediate_values?: { [key: string]: number }
value?: number
values?: number[]
system_attrs?: { [key: string]: any };
state?: number;
intermediate_values?: { [key: string]: number };
value?: number;
values?: number[];
}
interface JournalOpSetTrialParam extends JournalOpBase {
trial_id: number
param_name: string
param_value_internal: number
distribution: string
trial_id: number;
param_name: string;
param_value_internal: number;
distribution: string;
}
interface JournalOpSetTrialStateValue extends JournalOpBase {
trial_id: number
state: number
values?: number[]
datetime_start?: string
datetime_complete?: string
trial_id: number;
state: number;
values?: number[];
datetime_start?: string;
datetime_complete?: string;
}
interface JournalOpSetTrialIntermediateValue extends JournalOpBase {
trial_id: number
step: number
intermediate_value: number
trial_id: number;
step: number;
intermediate_value: number;
}
interface JournalOpSetTrialUserAttr extends JournalOpBase {
trial_id: number
trial_id: number;
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
user_attr: { [key: string]: any }
user_attr: { [key: string]: any };
}
const trialStateNumToTrialState = (state: number): TrialState => {
switch (state) {
case 0:
return "Running"
return "Running";
case 1:
return "Complete"
return "Complete";
case 2:
return "Pruned"
return "Pruned";
case 3:
return "Fail"
return "Fail";
case 4:
return "Waiting"
return "Waiting";
default:
return "Running"
return "Running";
}
}
};
const parseDistribution = (distribution: string): Distribution => {
const distributionJson = JSON.parse(distribution)
const distributionJson = JSON.parse(distribution);
if (distributionJson.name === "IntDistribution") {
return {
...distributionJson.attributes,
type: "IntDistribution",
}
};
} else if (distributionJson.name === "FloatDistribution") {
return {
...distributionJson.attributes,
type: "FloatDistribution",
}
};
} else {
return {
// TODO(gen740): support other types
@@ -110,59 +110,59 @@ const parseDistribution = (distribution: string): Distribution => {
return {
pytype: "str",
value: choice.toString(),
}
};
}),
}
};
}
}
};
class JournalStorage {
private studies: Study[] = []
private nextStudyId = 0
private studyIdToTrialIDs: Map<number, number[]> = new Map()
private trialIdToStudyId: Map<number, number> = new Map()
private trialID = 0
private studies: Study[] = [];
private nextStudyId = 0;
private studyIdToTrialIDs: Map<number, number[]> = new Map();
private trialIdToStudyId: Map<number, number> = new Map();
private trialID = 0;
public getStudies(): Study[] {
for (const study of this.studies) {
const unionUserAttrs: Set<string> = new Set()
const unionSearchSpace: Set<string> = new Set()
let intersectionSearchSpace: string[] = []
const unionUserAttrs: Set<string> = new Set();
const unionSearchSpace: Set<string> = new Set();
let intersectionSearchSpace: string[] = [];
study.trials.forEach((trial, index) => {
for (const userAttr of trial.user_attrs) {
unionUserAttrs.add(userAttr.key)
unionUserAttrs.add(userAttr.key);
}
for (const param of trial.params) {
unionSearchSpace.add(param.name)
unionSearchSpace.add(param.name);
}
if (index === 0) {
intersectionSearchSpace = Array.from(unionSearchSpace)
intersectionSearchSpace = Array.from(unionSearchSpace);
} else {
intersectionSearchSpace = intersectionSearchSpace.filter((name) => {
return trial.params.some((param) => param.name === name)
})
return trial.params.some((param) => param.name === name);
});
}
})
});
study.union_user_attrs = Array.from(unionUserAttrs).map((key) => {
return {
key: key,
sortable: false,
}
})
};
});
study.union_search_space = Array.from(unionSearchSpace).map((name) => {
return {
name: name,
}
})
};
});
study.intersection_search_space = intersectionSearchSpace.map((name) => {
return {
name: name,
}
})
};
});
}
return this.studies
return this.studies;
}
public applyCreateStudy(log: JournalOpCreateStudy): void {
@@ -174,20 +174,22 @@ class JournalStorage {
intersection_search_space: [],
union_user_attrs: [],
trials: [],
})
this.nextStudyId++
});
this.nextStudyId++;
}
public applyDeleteStudy(log: JournalOpDeleteStudy): void {
this.studies = this.studies.filter((item) => item.study_id !== log.study_id)
this.studies = this.studies.filter(
(item) => item.study_id !== log.study_id,
);
}
public applyCreateTrial(log: JournalOpCreateTrial): void {
const thisStudy = this.studies.find(
(item) => item.study_id === log.study_id
)
(item) => item.study_id === log.study_id,
);
if (thisStudy === undefined) {
return
return;
}
const params: TrialParam[] =
@@ -195,32 +197,32 @@ class JournalStorage {
? []
: Object.entries(log.params).map(([name, value]) => {
// biome-ignore lint/style/noNonNullAssertion: <explanation>
const distribution = parseDistribution(log.distributions![name])
const distribution = parseDistribution(log.distributions![name]);
return {
name: name,
param_internal_value: value,
param_external_type: distribution.type,
param_external_value: (() => {
if (distribution.type === "FloatDistribution") {
return value.toString()
return value.toString();
} else if (distribution.type === "IntDistribution") {
return value.toString()
return value.toString();
} else {
return distribution.choices[value]
return distribution.choices[value];
}
})(),
distribution: distribution,
}
})
};
});
const userAtter = log.user_attrs
? Object.entries(log.user_attrs).map(([key, value]) => {
return {
key: key,
value: value,
}
};
})
: []
: [];
thisStudy.trials.push({
trial_id: this.trialID,
@@ -229,11 +231,11 @@ class JournalStorage {
state: trialStateNumToTrialState(log.state ?? 0),
values: (() => {
if (log.value !== undefined) {
return [log.value]
return [log.value];
} else if (log.values !== undefined) {
return log.values
return log.values;
} else {
return undefined
return undefined;
}
})(),
params: params,
@@ -245,36 +247,36 @@ class JournalStorage {
datetime_complete: log.datetime_complete
? new Date(log.datetime_complete)
: undefined,
})
});
this.studyIdToTrialIDs.set(
log.study_id,
this.studyIdToTrialIDs.get(log.study_id)?.concat([this.trialID]) ?? [
this.trialID,
]
)
this.trialIdToStudyId.set(this.trialID, log.study_id)
this.trialID++
],
);
this.trialIdToStudyId.set(this.trialID, log.study_id);
this.trialID++;
}
private getStudyAndTrial(trial_id: number): [Study?, Trial?] {
const study = this.studies.find(
(item) => item.study_id === this.trialIdToStudyId.get(trial_id)
)
(item) => item.study_id === this.trialIdToStudyId.get(trial_id),
);
if (study === undefined) {
return [undefined, undefined]
return [undefined, undefined];
}
const trial = study.trials.find((item) => item.trial_id === trial_id)
const trial = study.trials.find((item) => item.trial_id === trial_id);
if (trial === undefined) {
return [study, undefined]
return [study, undefined];
}
return [study, trial]
return [study, trial];
}
public applySetTrialParam(log: JournalOpSetTrialParam) {
const [thisStudy, thisTrial] = this.getStudyAndTrial(log.trial_id)
const [thisStudy, thisTrial] = this.getStudyAndTrial(log.trial_id);
if (thisStudy === undefined || thisTrial === undefined) {
return
return;
}
thisTrial.params.push({
name: log.param_name,
@@ -282,51 +284,51 @@ class JournalStorage {
param_external_type: "FloatDistribution",
param_external_value: log.param_value_internal.toString(),
distribution: parseDistribution(log.distribution),
})
});
}
public applySetTrialStateValues(log: JournalOpSetTrialStateValue): void {
const [thisStudy, thisTrial] = this.getStudyAndTrial(log.trial_id)
const [thisStudy, thisTrial] = this.getStudyAndTrial(log.trial_id);
if (thisStudy === undefined || thisTrial === undefined) {
return
return;
}
thisTrial.state = trialStateNumToTrialState(log.state)
thisTrial.values = log.values
thisTrial.state = trialStateNumToTrialState(log.state);
thisTrial.values = log.values;
thisTrial.datetime_start = log.datetime_start
? new Date(log.datetime_start)
: undefined
: undefined;
thisTrial.datetime_complete = log.datetime_complete
? new Date(log.datetime_complete)
: undefined
: undefined;
}
public applySetTrialIntermediateValue(
log: JournalOpSetTrialIntermediateValue
log: JournalOpSetTrialIntermediateValue,
) {
const [thisStudy, thisTrial] = this.getStudyAndTrial(log.trial_id)
const [thisStudy, thisTrial] = this.getStudyAndTrial(log.trial_id);
if (thisStudy === undefined || thisTrial === undefined) {
return
return;
}
thisTrial.intermediate_values.push({
step: log.step,
value: log.intermediate_value,
})
});
}
public applySetTrialUserAttr(log: JournalOpSetTrialUserAttr) {
const [thisStudy, thisTrial] = this.getStudyAndTrial(log.trial_id)
const [thisStudy, thisTrial] = this.getStudyAndTrial(log.trial_id);
if (thisStudy === undefined || thisTrial === undefined) {
return
return;
}
for (const [key, value] of Object.entries(log.user_attr)) {
const index = thisTrial.user_attrs.findIndex((item) => item.key === key)
const index = thisTrial.user_attrs.findIndex((item) => item.key === key);
if (index !== -1) {
thisTrial.user_attrs[index].value = value.toString()
thisTrial.user_attrs[index].value = value.toString();
} else {
thisTrial.user_attrs.push({
key: key,
value: value.toString(),
})
});
}
}
}
@@ -334,58 +336,58 @@ class JournalStorage {
export const loadJournalStorage = (
arrayBuffer: ArrayBuffer,
setter: SetterOrUpdater<Study[]>
setter: SetterOrUpdater<Study[]>,
): void => {
const decoder = new TextDecoder("utf-8")
const logs = decoder.decode(arrayBuffer).split("\n")
const decoder = new TextDecoder("utf-8");
const logs = decoder.decode(arrayBuffer).split("\n");
const journalStorage = new JournalStorage()
const journalStorage = new JournalStorage();
for (const log of logs) {
if (log === "") {
continue
continue;
}
const parsedLog: JournalOpBase = JSON.parse(log)
const parsedLog: JournalOpBase = JSON.parse(log);
switch (parsedLog.op_code) {
case JournalOperation.CREATE_STUDY:
journalStorage.applyCreateStudy(parsedLog as JournalOpCreateStudy)
break
journalStorage.applyCreateStudy(parsedLog as JournalOpCreateStudy);
break;
case JournalOperation.DELETE_STUDY:
journalStorage.applyDeleteStudy(parsedLog as JournalOpDeleteStudy)
break
journalStorage.applyDeleteStudy(parsedLog as JournalOpDeleteStudy);
break;
case JournalOperation.SET_STUDY_USER_ATTR:
// Unsupported
break
break;
case JournalOperation.SET_STUDY_SYSTEM_ATTR:
// Unsupported
break
break;
case JournalOperation.CREATE_TRIAL:
journalStorage.applyCreateTrial(parsedLog as JournalOpCreateTrial)
break
journalStorage.applyCreateTrial(parsedLog as JournalOpCreateTrial);
break;
case JournalOperation.SET_TRIAL_PARAM:
journalStorage.applySetTrialParam(parsedLog as JournalOpSetTrialParam)
break
journalStorage.applySetTrialParam(parsedLog as JournalOpSetTrialParam);
break;
case JournalOperation.SET_TRIAL_STATE_VALUES:
journalStorage.applySetTrialStateValues(
parsedLog as JournalOpSetTrialStateValue
)
break
parsedLog as JournalOpSetTrialStateValue,
);
break;
case JournalOperation.SET_TRIAL_INTERMEDIATE_VALUE:
journalStorage.applySetTrialIntermediateValue(
parsedLog as JournalOpSetTrialIntermediateValue
)
break
parsedLog as JournalOpSetTrialIntermediateValue,
);
break;
case JournalOperation.SET_TRIAL_USER_ATTR:
journalStorage.applySetTrialUserAttr(
parsedLog as JournalOpSetTrialUserAttr
)
break
parsedLog as JournalOpSetTrialUserAttr,
);
break;
case JournalOperation.SET_TRIAL_SYSTEM_ATTR:
// Unsupported
break
break;
}
}
const studies = journalStorage.getStudies()
setter((prev) => [...prev, ...studies])
}
const studies = journalStorage.getStudies();
setter((prev) => [...prev, ...studies]);
};
+144 -142
View File
@@ -1,35 +1,37 @@
// @ts-ignore
import sqlite3InitModule from "@sqlite.org/sqlite-wasm"
import { SetterOrUpdater } from "recoil"
import sqlite3InitModule from "@sqlite.org/sqlite-wasm";
import { SetterOrUpdater } from "recoil";
export const loadSQLite3Storage = async (
arrayBuffer: ArrayBuffer,
setter: SetterOrUpdater<Study[]>
setter: SetterOrUpdater<Study[]>,
) => {
const sqlite3Storage = new SQLite3Storage(arrayBuffer)
const studySummaries = await sqlite3Storage.getStudies()
const sqlite3Storage = new SQLite3Storage(arrayBuffer);
const studySummaries = await sqlite3Storage.getStudies();
const studies = (
await Promise.all(
studySummaries.map((summary) => sqlite3Storage.getStudy(summary.study_id))
studySummaries.map((summary) =>
sqlite3Storage.getStudy(summary.study_id),
),
)
).filter((s) => s !== null) as Study[]
setter((prev) => [...prev, ...studies])
}
).filter((s) => s !== null) as Study[];
setter((prev) => [...prev, ...studies]);
};
type SQLite3DB = {
exec(options: {
sql: string
sql: string;
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
callback: (...args: any[]) => void
}): void
}
callback: (...args: any[]) => void;
}): void;
};
export class SQLite3Storage implements OptunaStorage {
db: Promise<SQLite3DB>
summaries_cache: StudySummary[] | null
db: Promise<SQLite3DB>;
summaries_cache: StudySummary[] | null;
constructor(arrayBuffer: ArrayBuffer) {
this.db = this.initDB(arrayBuffer)
this.summaries_cache = null
this.db = this.initDB(arrayBuffer);
this.summaries_cache = null;
}
async initDB(arrayBuffer: ArrayBuffer): Promise<SQLite3DB> {
@@ -38,8 +40,8 @@ export class SQLite3Storage implements OptunaStorage {
printErr: console.log,
// @ts-ignore
}).then((sqlite3) => {
const p = sqlite3.wasm.allocFromTypedArray(arrayBuffer)
const db = new sqlite3.oo1.DB()
const p = sqlite3.wasm.allocFromTypedArray(arrayBuffer);
const db = new sqlite3.oo1.DB();
const rc = sqlite3.capi.sqlite3_deserialize(
// @ts-ignore
db.pointer,
@@ -47,72 +49,72 @@ export class SQLite3Storage implements OptunaStorage {
p,
arrayBuffer.byteLength,
arrayBuffer.byteLength,
sqlite3.capi.SQLITE_DESERIALIZE_FREEONCLOSE
)
db.checkRc(rc)
return db
})
sqlite3.capi.SQLITE_DESERIALIZE_FREEONCLOSE,
);
db.checkRc(rc);
return db;
});
}
getStudies = async (): Promise<StudySummary[]> => {
const db = await this.db
this.summaries_cache = getStudySummaries(db)
return this.summaries_cache
}
const db = await this.db;
this.summaries_cache = getStudySummaries(db);
return this.summaries_cache;
};
getStudy = async (idx: number): Promise<Study | null> => {
const db = await this.db
const schemaVersion = getSchemaVersion(db)
const db = await this.db;
const schemaVersion = getSchemaVersion(db);
if (!isSupportedSchema(schemaVersion)) {
return null
return null;
}
if (this.summaries_cache === null) {
this.summaries_cache = getStudySummaries(db)
this.summaries_cache = getStudySummaries(db);
}
const summary = this.summaries_cache[idx]
const summary = this.summaries_cache[idx];
if (summary === undefined) {
return null
return null;
}
return getStudy(db, schemaVersion, summary)
}
return getStudy(db, schemaVersion, summary);
};
}
const getSchemaVersion = (db: SQLite3DB): string => {
let schemaVersion = ""
let schemaVersion = "";
db.exec({
sql: "SELECT version_num FROM alembic_version LIMIT 1",
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
callback: (vals: any[]) => {
schemaVersion = vals[0]
schemaVersion = vals[0];
},
})
return schemaVersion
}
});
return schemaVersion;
};
const isSupportedSchema = (schemaVersion: string): boolean => {
const lowestVersion = "v2.6.0.a" // supported: "v3.2.0.a", "v3.0.0.{a,b,c,d}", "v2.6.0.a"
if (schemaVersion === lowestVersion) return true
return isGreaterSchemaVersion(schemaVersion, lowestVersion)
}
const lowestVersion = "v2.6.0.a"; // supported: "v3.2.0.a", "v3.0.0.{a,b,c,d}", "v2.6.0.a"
if (schemaVersion === lowestVersion) return true;
return isGreaterSchemaVersion(schemaVersion, lowestVersion);
};
const isGreaterSchemaVersion = (
leftVersion: string,
rightVersion: string
rightVersion: string,
): boolean => {
// return leftVersion > rightVersion
const leftSuffix = leftVersion.split(".").reverse()[0]
const rightSuffix = rightVersion.split(".").reverse()[0]
const leftVersion_ = leftVersion.replace(/\D/g, "")
const rightVersion_ = rightVersion.replace(/\D/g, "")
const leftSuffix = leftVersion.split(".").reverse()[0];
const rightSuffix = rightVersion.split(".").reverse()[0];
const leftVersion_ = leftVersion.replace(/\D/g, "");
const rightVersion_ = rightVersion.replace(/\D/g, "");
const left = Number(leftVersion_)
const right = Number(rightVersion_)
if (left === right) return leftSuffix > rightSuffix
return left > right
}
const left = Number(leftVersion_);
const right = Number(rightVersion_);
if (left === right) return leftSuffix > rightSuffix;
return left > right;
};
const getStudySummaries = (db: SQLite3DB): StudySummary[] => {
const summaries: StudySummary[] = []
const summaries: StudySummary[] = [];
db.exec({
sql:
"SELECT s.study_id, s.study_name, sd.direction, sd.objective" +
@@ -120,31 +122,31 @@ const getStudySummaries = (db: SQLite3DB): StudySummary[] => {
" ON s.study_id = sd.study_id ORDER BY sd.study_direction_id",
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
callback: (vals: any[]) => {
const studyId = vals[0]
const studyName = vals[1]
const studyId = vals[0];
const studyName = vals[1];
const direction: StudyDirection =
vals[2] === "MINIMIZE" ? "minimize" : "maximize"
const objective = vals[3]
vals[2] === "MINIMIZE" ? "minimize" : "maximize";
const objective = vals[3];
if (objective === 0) {
summaries.push({
study_id: studyId,
study_name: studyName,
directions: [direction],
})
return
});
return;
}
const index = summaries.findIndex((s) => s.study_id === studyId)
summaries[index].directions.push(direction)
const index = summaries.findIndex((s) => s.study_id === studyId);
summaries[index].directions.push(direction);
},
})
return summaries
}
});
return summaries;
};
const getStudy = (
db: SQLite3DB,
schemaVersion: string,
summary: StudySummary
summary: StudySummary,
): Study => {
const study: Study = {
study_id: summary.study_id,
@@ -154,57 +156,57 @@ const getStudy = (
intersection_search_space: [],
union_user_attrs: [],
trials: [],
}
};
let intersection_search_space: Set<SearchSpaceItem> = new Set()
study.trials = getTrials(db, summary.study_id, schemaVersion)
let intersection_search_space: Set<SearchSpaceItem> = new Set();
study.trials = getTrials(db, summary.study_id, schemaVersion);
for (const trial of study.trials) {
const userAttrs = getTrialUserAttributes(db, trial.trial_id)
const userAttrs = getTrialUserAttributes(db, trial.trial_id);
for (const attr of userAttrs) {
if (study.union_user_attrs.findIndex((s) => s.key === attr.key) === -1) {
study.union_user_attrs.push({ key: attr.key, sortable: false })
study.union_user_attrs.push({ key: attr.key, sortable: false });
}
}
const params = getTrialParams(db, trial.trial_id)
const param_names = new Set<string>()
const params = getTrialParams(db, trial.trial_id);
const param_names = new Set<string>();
for (const param of params) {
param_names.add(param.name)
param_names.add(param.name);
if (
study.union_search_space.findIndex((s) => s.name === param.name) === -1
) {
study.union_search_space.push({ name: param.name })
study.union_search_space.push({ name: param.name });
}
}
if (intersection_search_space.size === 0) {
param_names.forEach((s) => {
intersection_search_space.add({ name: s })
})
intersection_search_space.add({ name: s });
});
} else {
intersection_search_space = new Set(
Array.from(intersection_search_space).filter((s) =>
param_names.has(s.name)
)
)
param_names.has(s.name),
),
);
}
trial.params = params
trial.user_attrs = userAttrs
trial.params = params;
trial.user_attrs = userAttrs;
}
study.intersection_search_space = Array.from(intersection_search_space)
return study
}
study.intersection_search_space = Array.from(intersection_search_space);
return study;
};
const getTrials = (
db: SQLite3DB,
studyId: number,
schemaVersion: string
schemaVersion: string,
): Trial[] => {
const trials: Trial[] = []
const trials: Trial[] = [];
db.exec({
sql: `SELECT trial_id, number, state, datetime_start, datetime_complete FROM trials WHERE study_id = ${studyId} ORDER BY number`,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
callback: (vals: any[]) => {
const trialId = vals[0]
const trialId = vals[0];
const state: TrialState =
vals[2] === "COMPLETE"
? "Complete"
@@ -214,7 +216,7 @@ const getTrials = (
? "Running"
: vals[2] === "WAITING"
? "Waiting"
: "Fail"
: "Fail";
const trial: Trial = {
trial_id: trialId,
number: vals[1],
@@ -224,25 +226,25 @@ const getTrials = (
intermediate_values: getTrialIntermediateValues(
db,
trialId,
schemaVersion
schemaVersion,
),
params: [], // Set this column later
user_attrs: [], // Set this column later
datetime_start: vals[3],
datetime_complete: vals[4],
}
trials.push(trial)
};
trials.push(trial);
},
})
return trials
}
});
return trials;
};
const getTrialValues = (
db: SQLite3DB,
trialId: number,
schemaVersion: string
schemaVersion: string,
): number[] => {
const values: number[] = []
const values: number[] = [];
if (isGreaterSchemaVersion(schemaVersion, "v3.0.0.c")) {
db.exec({
sql: `SELECT value, value_type FROM trial_values WHERE trial_id = ${trialId} ORDER BY objective`,
@@ -253,59 +255,59 @@ const getTrialValues = (
? -Infinity
: vals[1] === "INF_POS"
? Infinity
: vals[0]
)
: vals[0],
);
},
})
});
} else {
db.exec({
sql: `SELECT value FROM trial_values WHERE trial_id = ${trialId} ORDER BY objective`,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
callback: (vals: any[]) => {
values.push(vals[0])
values.push(vals[0]);
},
})
});
}
return values
}
return values;
};
const getTrialParams = (db: SQLite3DB, trialId: number): TrialParam[] => {
const params: TrialParam[] = []
const params: TrialParam[] = [];
db.exec({
sql: `SELECT param_name, param_value, distribution_json FROM trial_params WHERE trial_id = ${trialId}`,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
callback: (vals: any[]) => {
const distribution = parseDistributionJSON(vals[2])
const distribution = parseDistributionJSON(vals[2]);
params.push({
name: vals[0],
param_internal_value: vals[1],
param_external_type: distribution.type,
param_external_value: paramInternalValueToExternalValue(
distribution,
vals[1]
vals[1],
),
distribution: distribution,
})
});
},
})
return params
}
});
return params;
};
const paramInternalValueToExternalValue = (
distribution: Distribution,
internalValue: number
internalValue: number,
): CategoricalChoiceType => {
if (distribution.type === "FloatDistribution") {
return internalValue.toString()
return internalValue.toString();
}
if (distribution.type === "IntDistribution") {
return internalValue.toString()
return internalValue.toString();
}
return distribution.choices[internalValue]
}
return distribution.choices[internalValue];
};
const parseDistributionJSON = (t: string): Distribution => {
const parsed = JSON.parse(t)
const parsed = JSON.parse(t);
if (parsed.name === "FloatDistribution") {
return {
type: "FloatDistribution",
@@ -313,7 +315,7 @@ const parseDistributionJSON = (t: string): Distribution => {
high: parsed.attributes.high as number,
step: parsed.attributes.step as number,
log: parsed.attributes.log as boolean,
}
};
}
if (parsed.name === "UniformDistribution") {
return {
@@ -322,7 +324,7 @@ const parseDistributionJSON = (t: string): Distribution => {
high: parsed.attributes.high as number,
step: null,
log: false,
}
};
}
if (parsed.name === "LogUniformDistribution") {
return {
@@ -331,7 +333,7 @@ const parseDistributionJSON = (t: string): Distribution => {
high: parsed.attributes.high as number,
step: null,
log: true,
}
};
}
if (parsed.name === "DiscreteUniformDistribution") {
return {
@@ -340,7 +342,7 @@ const parseDistributionJSON = (t: string): Distribution => {
high: parsed.attributes.high as number,
step: parsed.attributes.q,
log: false,
}
};
}
if (parsed.name === "IntDistribution") {
return {
@@ -349,7 +351,7 @@ const parseDistributionJSON = (t: string): Distribution => {
high: parsed.attributes.high as number,
step: parsed.attributes.step as number,
log: parsed.attributes.log as boolean,
}
};
}
if (parsed.name === "IntUniformDistribution") {
return {
@@ -358,7 +360,7 @@ const parseDistributionJSON = (t: string): Distribution => {
high: parsed.attributes.high as number,
step: parsed.attributes.step as number,
log: false,
}
};
}
if (parsed.name === "IntLogUniformDistribution") {
return {
@@ -367,19 +369,19 @@ const parseDistributionJSON = (t: string): Distribution => {
high: parsed.attributes.high as number,
step: parsed.attributes.step as number,
log: true,
}
};
}
return {
type: "CategoricalDistribution",
choices: parsed.attributes.choices,
}
}
};
};
const getTrialUserAttributes = (
db: SQLite3DB,
trialId: number
trialId: number,
): Attribute[] => {
const attrs: Attribute[] = []
const attrs: Attribute[] = [];
db.exec({
sql: `SELECT key, value_json FROM trial_user_attributes WHERE trial_id = ${trialId}`,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
@@ -387,18 +389,18 @@ const getTrialUserAttributes = (
attrs.push({
key: vals[0],
value: vals[1],
})
});
},
})
return attrs
}
});
return attrs;
};
const getTrialIntermediateValues = (
db: SQLite3DB,
trialId: number,
schemaVersion: string
schemaVersion: string,
): TrialIntermediateValue[] => {
const values: TrialIntermediateValue[] = []
const values: TrialIntermediateValue[] = [];
if (isGreaterSchemaVersion(schemaVersion, "v3.0.0.c")) {
db.exec({
sql: `SELECT step, intermediate_value, intermediate_value_type FROM trial_intermediate_values WHERE trial_id = ${trialId} ORDER BY step`,
@@ -414,9 +416,9 @@ const getTrialIntermediateValues = (
: vals[2] === "NAN"
? NaN
: vals[1],
})
});
},
})
});
} else {
db.exec({
sql: `SELECT step, intermediate_value FROM trial_intermediate_values WHERE trial_id = ${trialId} ORDER BY step`,
@@ -425,9 +427,9 @@ const getTrialIntermediateValues = (
values.push({
step: vals[0],
value: vals[1],
})
});
},
})
});
}
return values
}
return values;
};