Plate-budget acquisition#10
Merged
Merged
Conversation
Replace the flat query count (k_per_iteration) with three physical plate parameters: plate_size, wells_per_ps, and wells_per_drc. CostAwareGreedyAcquisition.select() now walks the ranked candidate list in score order and hard-stops when the next candidate would push total wells over plate_size. Remaining candidates are deferred to the next iteration where all scores are refreshed on the updated model. - moal/config.py: ActiveLearningLoopConfig gains plate_size=1536, wells_per_ps=1, wells_per_drc=13; k_per_iteration removed - moal/acquisition.py: select() signature updated; greedy loop tracks wells_used and breaks on overflow; plate_size=0 guard replaces k=0 - moal/loop.py: run() signature updated; both acquisition.select() call sites updated; campaign banner updated - moal/cli.py: passes the three new config fields to loop.run() - examples/default_config.yaml: k_per_iteration replaced with the three new fields with explanatory comments - tests/test_acquisition.py: all select() calls updated; two new tests: test_drc_cost_stops_at_plate_boundary and test_wells_used_never_exceeds_plate_size - tests/test_loop.py: K=5 replaced with PLATE_SIZE=5/WELLS_PS=1/WELLS_DRC=1 - tests/test_cli.py: inline YAML snippets and assertions updated - README.md / copilot-instructions.md: docs updated Backwards compat: k_per_iteration=k is reproduced by plate_size=k, wells_per_ps=1, wells_per_drc=1. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Each bar segment (DRC, PS→DRC, PS) in the per-iteration cost breakdown panel now shows both the number of queries and the dollar cost on hover, e.g. 'DRC / 10 queries / $100'. - loop.py: compute iter_n_drc_new, iter_n_drc_upgrade, iter_n_ps from new_records and forward them to dashboard.update() - dashboard.py: update() accepts iter_n_drc_new, iter_n_upgrades, iter_n_ps (default 0 for backwards compat); stores counts in the per-iteration snapshot; adds customdata + hovertemplate to the three go.Bar traces in _build_figure() Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the flat
k_per_iterationacquisition parameter with a physical plate-budget system and enhances the cost bar chart in the live dashboard to display per-category query counts alongside dollar costs on hover.Motivation
k_per_iterationwas a dimensionless count that didn't map to real experimental constraints. In practice, a wet-lab run fills a physical plate: each Primary Screen (PS) consumes 1 well, each Dose-Response Curve (DRC) consumes many more (e.g., 13 for a 13-point singlet DRC). Expressing the budget in wells rather than queries makes the config directly interpretable by experimentalists and naturally handles the asymmetric cost of DRC vs PS queries.Changes
moal/config.pyActiveLearningLoopConfigdropsk_per_iterationand gains three new fields:plate_size1536wells_per_ps1wells_per_drc13moal/acquisition.pyCostAwareGreedyAcquisition.select()replaces thek: intparameter withplate_size,wells_per_ps,wells_per_drc. The selection loop now:wells_usedas each candidate is considered.wells_usedaboveplate_size— it does not skip that candidate and search for a cheaper one. Remaining candidates are deferred to the next iteration, where the model will rescore them on the updated labeled pool.The undersupply warning message is updated to report
plate_size,wells_per_ps, andwells_per_drcrather than counts.moal/loop.pyActiveLearningLoop.run()signature updated:k_per_iteration→plate_size,wells_per_ps,wells_per_drc.acquisition.select()call sites updated (pre-loop seed + in-loop body).iter_n_ps,iter_n_drc_new,iter_n_drc_upgrade) are computed fromnew_recordsafter each oracle query and forwarded todashboard.update().moal/dashboard.pyLiveDashboard.update()gains three optional parameters (defaulting to0for backwards compatibility with any existing serialized snapshot data):iter_n_drc_new— new first-pass DRC queriesiter_n_upgrades— PS→DRC upgrade queriesiter_n_ps— PS queriesThese are stored per-iteration in the snapshot dict and surfaced as
customdataon the three stacked bar traces in the per-iteration cost breakdown panel (panel 2). Hover tooltips now read, e.g.:moal/cli.pyExtracts
plate_size,wells_per_ps,wells_per_drcfrom config and passes them through toloop.run().examples/default_config.yamlk_per_iteration: 100replaced with the three new fields and descriptive inline comments:Tests
tests/test_acquisition.pyAll existing
select()call sites updated to the new signature. Two new testsadded:
test_drc_cost_stops_at_plate_boundary— verifies that a DRC candidate that would overflow the plate causes the loop to stop, even though there are remaining candidates with lower scores.test_wells_used_never_exceeds_plate_size— property-style test across a range of plate sizes confirmingwells_usednever exceedsplate_size.tests/test_loop.pyK = 5constant replaced withPLATE_SIZE = 5,WELLS_PS = 1,WELLS_DRC = 1(equivalent behaviour). Allloop.run()calls updated.