Skip to content

Commit

Permalink
Merge pull request #329 from BoostV/calculate-suggestion-count
Browse files Browse the repository at this point in the history
Calculate suggestion count
  • Loading branch information
j-or authored Sep 27, 2023
2 parents bd3ef90 + 44a5474 commit 6748696
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 136 deletions.
6 changes: 6 additions & 0 deletions .changeset/clean-mails-accept.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@boostv/process-optimizer-frontend-core': patch
'@boostv/process-optimizer-frontend-ui': patch
---

Improve calculation of the number of experiments to suggest
7 changes: 6 additions & 1 deletion packages/core/src/context/experiment/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
calculateSpace,
experimentResultSchema,
} from '@core/common'
import { selectCalculatedSuggestionCountFromExperiment } from './experiment-selectors'

export const createFetchExperimentResultRequest = (
experiment: ExperimentType
Expand All @@ -25,7 +26,11 @@ export const createFetchExperimentResultRequest = (
experiment.scoreVariables,
experiment.dataPoints
),
extras: extras,
extras: {
...extras,
experimentSuggestionCount:
selectCalculatedSuggestionCountFromExperiment(experiment),
},
optimizerConfig: {
acqFunc: cfg.acqFunc,
baseEstimator: cfg.baseEstimator,
Expand Down
20 changes: 1 addition & 19 deletions packages/core/src/context/experiment/experiment-reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,6 @@ const calculateXi = (state: ExperimentType) => {
)
}

const calculateExperimentSuggestionCount = (state: ExperimentType) => {
const dataPoints = state.dataPoints.filter(
d => d.meta.enabled && d.meta.valid
).length
const initialPoints = state.optimizerConfig.initialPoints
if (dataPoints >= initialPoints) {
return 1
}
return initialPoints
}

export type ExperimentAction =
| {
type: 'setSwVersion'
Expand Down Expand Up @@ -371,8 +360,6 @@ export const experimentReducer = produce(
state.optimizerConfig = experimentSchema.shape.optimizerConfig.parse(
action.payload
)
state.extras.experimentSuggestionCount =
calculateExperimentSuggestionCount(state)
break
case 'registerResult':
state.lastEvaluationHash = md5(
Expand All @@ -388,8 +375,6 @@ export const experimentReducer = produce(
state.scoreVariables,
action.payload
)
state.extras.experimentSuggestionCount =
calculateExperimentSuggestionCount(state)
state.optimizerConfig.xi = calculateXi(state)
break
case 'experiment/toggleMultiObjective':
Expand Down Expand Up @@ -441,8 +426,6 @@ export const experimentReducer = produce(
dimensions: [action.payload],
})
}
state.extras.experimentSuggestionCount =
calculateExperimentSuggestionCount(state)
break
}
case 'experiment/removeVariableFromConstraintSum': {
Expand All @@ -452,8 +435,7 @@ export const experimentReducer = produce(
d => d !== action.payload
)
}
state.extras.experimentSuggestionCount =
calculateExperimentSuggestionCount(state)

break
}
default:
Expand Down
116 changes: 116 additions & 0 deletions packages/core/src/context/experiment/experiment-selectors.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { initialState, State } from '@core/context/experiment/store'
import {
selectCalculatedSuggestionCount,
selectId,
selectIsConstraintActive,
selectIsInitializing,
selectIsMultiObjective,
selectIsSuggestionCountEditable,
} from './experiment-selectors'
import { rootReducer } from './reducers'
import { createDataPoints } from './test-utils'
import { ExperimentType } from '@core/common'

describe('Experiment selectors', () => {
let state: State
Expand Down Expand Up @@ -59,4 +64,115 @@ describe('Experiment selectors', () => {
expect(after2ndToggle).toEqual(before)
})
})

describe('selectIsSuggestionCountEditable', () => {
const constraints: ExperimentType['constraints'] = [
{
type: 'sum',
dimensions: ['a', 'b'],
value: 100,
},
]
it.each([
//data points < initial points, constraint active
[1, 2, constraints, true],
//data points < initial points, constraint NOT active
[1, 2, [], true],
//data points = initial points, constraint active
[1, 1, constraints, false],
//data points = initial points, constraint NOT active
[1, 1, [], true],
//data points > initial points, constraint active
[2, 1, constraints, false],
//data points > initial points, constraint NOT active
[2, 1, [], true],
])(
'should be true when data points < intial points or constraints are active',
(dataPoints, initialPoints, constraints, result) => {
const editable = selectIsSuggestionCountEditable({
...initialState,
experiment: {
...initialState.experiment,
dataPoints: createDataPoints(dataPoints),
optimizerConfig: {
...initialState.experiment.optimizerConfig,
initialPoints,
},
constraints,
},
})
expect(editable).toBe(result)
}
)
})

describe('selectCalculatedSuggestionCount', () => {
const suggestionCount = 5
const constraints: ExperimentType['constraints'] = [
{
type: 'sum',
dimensions: ['a', 'b'],
value: 100,
},
]
it.each([
//data points < initial points, constraint active -> initial points
[1, 2, constraints, 2],
//data points < initial points, constraint NOT active -> initial points
[1, 2, [], 2],
//data points = initial points, constraint active -> 1
[1, 1, constraints, 1],
//data points = initial points, constraint NOT active -> suggestionCount
[1, 1, [], suggestionCount],
//data points > initial points, constraint active -> 1
[2, 1, constraints, 1],
//data points > initial points, constraint NOT active -> suggestionCount
[2, 1, [], suggestionCount],
])(
'should return correct value',
(dataPoints, initialPoints, constraints, result) => {
const editable = selectCalculatedSuggestionCount({
...initialState,
experiment: {
...initialState.experiment,
dataPoints: createDataPoints(dataPoints),
optimizerConfig: {
...initialState.experiment.optimizerConfig,
initialPoints,
},
constraints,
extras: {
...initialState.experiment.extras,
experimentSuggestionCount: suggestionCount,
},
},
})
expect(editable).toBe(result)
}
)
})

describe('selectIsConstraintActive', () => {
it.each([
[['a', 'b', 'c'], true],
[['a', 'b'], true],
[['a'], false],
[[], false],
])(
'should return true when number of sum constraint variables > 1',
(dimensions, result) => {
const editable = selectIsConstraintActive({
...initialState.experiment,
constraints: [
{
type: 'sum',
value: 100,
dimensions,
},
],
})
expect(editable).toBe(result)
}
)
})
})
55 changes: 51 additions & 4 deletions packages/core/src/context/experiment/experiment-selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ export const selectDataPoints = (state: State) =>
selectExperiment(state).dataPoints

export const selectActiveDataPoints = (state: State) =>
selectExperiment(state).dataPoints.filter(d => d.meta.valid && d.meta.enabled)
selectActiveDataPointsFromExperiment(selectExperiment(state))

export const selectActiveDataPointsFromExperiment = (
experiment: ExperimentType
) => experiment.dataPoints.filter(d => d.meta.valid && d.meta.enabled)

export const selectExpectedMinimum = (state: State) =>
selectExperiment(state).results.expectedMinimum
Expand Down Expand Up @@ -51,7 +55,50 @@ export const selectActiveVariableNames = (state: State): string[] => {
)
}

export const selectSumConstraint = (state: State) => {
const experiment = selectExperiment(state)
return experiment.constraints.find(c => c.type === 'sum')
export const selectSumConstraint = (state: State) =>
selectSumConstraintFromExperiment(selectExperiment(state))

export const selectSumConstraintFromExperiment = (experiment: ExperimentType) =>
experiment.constraints.find(c => c.type === 'sum')

export const selectIsConstraintActive = (experiment: ExperimentType) =>
(selectSumConstraintFromExperiment(experiment)?.dimensions.length ?? 0) > 1

export const selectInitialPoints = (state: State) =>
selectInitialPointsFromExperiment(selectExperiment(state))

export const selectInitialPointsFromExperiment = (experiment: ExperimentType) =>
experiment.optimizerConfig.initialPoints

export const selectIsSuggestionCountEditable = (state: State) => {
const dataPoints = selectActiveDataPoints(state)
const initialPoints = selectInitialPoints(state)
return (
dataPoints.length < initialPoints ||
!selectIsConstraintActive(selectExperiment(state))
)
}

export const selectSuggestionCountFromExperiment = (
experiment: ExperimentType
) =>
Number.isInteger(experiment.extras['experimentSuggestionCount'])
? Number(experiment.extras['experimentSuggestionCount'])
: 1

export const selectCalculatedSuggestionCount = (state: State) =>
selectCalculatedSuggestionCountFromExperiment(selectExperiment(state))

export const selectCalculatedSuggestionCountFromExperiment = (
experiment: ExperimentType
) => {
const dataPoints = selectActiveDataPointsFromExperiment(experiment).length
const initialPoints = selectInitialPointsFromExperiment(experiment)

if (dataPoints < initialPoints) {
return initialPoints
} else if (selectIsConstraintActive(experiment)) {
return 1
}
return selectSuggestionCountFromExperiment(experiment)
}
Loading

0 comments on commit 6748696

Please sign in to comment.