@jetta/cargo-stabilizer 0.1.0-7 → 0.1.0-8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/build/core/candidates/candidate_generator.d.ts +1 -1
- package/build/core/candidates/candidate_generator.js +21 -7
- package/build/core/candidates/collect_container_slots.d.ts +16 -0
- package/build/core/candidates/collect_container_slots.d.ts.map +1 -0
- package/build/core/candidates/collect_container_slots.js +20 -0
- package/build/core/candidates/enumerate_supporter_top_slots.d.ts +11 -0
- package/build/core/candidates/enumerate_supporter_top_slots.d.ts.map +1 -0
- package/build/core/candidates/enumerate_supporter_top_slots.js +36 -0
- package/build/core/move/apply_move.d.ts +2 -0
- package/build/core/move/apply_move.d.ts.map +1 -1
- package/build/core/strategies/reorder/BeamSearchReorder.d.ts.map +1 -1
- package/build/core/strategies/reorder/BeamSearchReorder.js +2 -1
- package/build/core/strategies/reorder/select_beam_expansion_candidates.d.ts +9 -0
- package/build/core/strategies/reorder/select_beam_expansion_candidates.d.ts.map +1 -0
- package/build/core/strategies/reorder/select_beam_expansion_candidates.js +28 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,7 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
11
11
|
- Strict English internal I/O contract with bidirectional cargo-movement wire mapper (`map_wire_input_to_contract`, `map_contract_to_wire_output`).
|
|
12
12
|
- Organization gates: waypoint Z zones, macro delivery order (`preserve_tie_block_organization`), and milkrun wall reservation (`enforce_milkrun_wall_reservation`).
|
|
13
13
|
- Empty-space candidate discovery for floor and elevated slots via `@jetta/empty-spaces-manager`.
|
|
14
|
+
- Supporter-top candidate slots aligned to each stacked item footprint, included in beam expansion (`top_k ∪ supporter_top`).
|
|
14
15
|
- Public contract exports: `parse_stabilizer_input`, `parse_stabilizer_output`, `safe_parse_stabilizer_input`, `safe_parse_stabilizer_output`, and related domain types.
|
|
15
16
|
|
|
16
17
|
### Changed
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { MoveCandidate } from '../move/apply_move.js';
|
|
2
2
|
import type { CandidateGenerationContext } from './candidate_context.js';
|
|
3
3
|
/**
|
|
4
|
-
* Generates ranked candidate slots from empty-space regions
|
|
4
|
+
* Generates ranked candidate slots from empty-space regions and supporter tops.
|
|
5
5
|
* @param context - Candidate generation context.
|
|
6
6
|
* @returns Candidate moves sorted floor-first, same container preferred.
|
|
7
7
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { collect_container_slots } from './collect_container_slots.js';
|
|
2
2
|
import { is_candidate_valid } from './candidate_validation.js';
|
|
3
3
|
import { rank_candidates } from './rank_candidates.js';
|
|
4
4
|
/**
|
|
5
|
-
* Generates ranked candidate slots from empty-space regions
|
|
5
|
+
* Generates ranked candidate slots from empty-space regions and supporter tops.
|
|
6
6
|
* @param context - Candidate generation context.
|
|
7
7
|
* @returns Candidate moves sorted floor-first, same container preferred.
|
|
8
8
|
*/
|
|
@@ -11,18 +11,32 @@ export function generate_candidates(context) {
|
|
|
11
11
|
return rank_candidates(candidates, context.loose.container_index);
|
|
12
12
|
}
|
|
13
13
|
function build_container_candidates(context, container, target_index) {
|
|
14
|
-
const slots = enumerate_empty_space_slots(container, context.loose.item, context.loose.item_id);
|
|
15
14
|
const candidates = [];
|
|
16
|
-
for (const
|
|
17
|
-
if (!is_candidate_valid(context, target_index, position)) {
|
|
15
|
+
for (const tagged of collect_container_slots(container, context.loose.item, context.loose.item_id)) {
|
|
16
|
+
if (!is_candidate_valid(context, target_index, tagged.position)) {
|
|
18
17
|
continue;
|
|
19
18
|
}
|
|
20
19
|
candidates.push({
|
|
21
20
|
item_id: context.loose.item_id,
|
|
22
21
|
source_container_index: context.loose.container_index,
|
|
23
22
|
target_container_index: target_index,
|
|
24
|
-
new_position: position
|
|
23
|
+
new_position: tagged.position,
|
|
24
|
+
slot_kind: tagged.slot_kind
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
return candidates;
|
|
27
|
+
return unique_kind_positions(candidates);
|
|
28
|
+
}
|
|
29
|
+
function unique_kind_positions(candidates) {
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
const unique = [];
|
|
32
|
+
for (const candidate of candidates) {
|
|
33
|
+
const position = candidate.new_position;
|
|
34
|
+
const key = `${position.x}:${position.y}:${position.z}:${candidate.target_container_index}`;
|
|
35
|
+
if (seen.has(key)) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
seen.add(key);
|
|
39
|
+
unique.push(candidate);
|
|
40
|
+
}
|
|
41
|
+
return unique;
|
|
28
42
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { StabilizerContainer } from '../validation/contract/stabilizer_domain_schema.js';
|
|
2
|
+
import type { CandidateSlotKind } from '../move/apply_move.js';
|
|
3
|
+
import type { EmptySpaceSlot } from './enumerate_empty_space_slots.js';
|
|
4
|
+
export interface TaggedSlot {
|
|
5
|
+
position: EmptySpaceSlot;
|
|
6
|
+
slot_kind: CandidateSlotKind;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Collects empty-space origins and per-supporter top origins, supporter first.
|
|
10
|
+
* @param container - Target container layout.
|
|
11
|
+
* @param item - Loose item to place.
|
|
12
|
+
* @param exclude_item_id - Loose item id omitted from obstacles and supporters.
|
|
13
|
+
* @returns Tagged slots with supporter-top entries before empty-space entries.
|
|
14
|
+
*/
|
|
15
|
+
export declare function collect_container_slots(container: StabilizerContainer, item: StabilizerContainer['items'][number], exclude_item_id: string): TaggedSlot[];
|
|
16
|
+
//# sourceMappingURL=collect_container_slots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect_container_slots.d.ts","sourceRoot":"","sources":["../../../src/core/candidates/collect_container_slots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oDAAoD,CAAA;AAC7F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAItE,MAAM,WAAW,UAAU;IAEvB,QAAQ,EAAE,cAAc,CAAA;IACxB,SAAS,EAAE,iBAAiB,CAAA;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACnC,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAC1C,eAAe,EAAE,MAAM,GACxB,UAAU,EAAE,CAQd"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { enumerate_empty_space_slots } from './enumerate_empty_space_slots.js';
|
|
2
|
+
import { enumerate_supporter_top_slots } from './enumerate_supporter_top_slots.js';
|
|
3
|
+
/**
|
|
4
|
+
* Collects empty-space origins and per-supporter top origins, supporter first.
|
|
5
|
+
* @param container - Target container layout.
|
|
6
|
+
* @param item - Loose item to place.
|
|
7
|
+
* @param exclude_item_id - Loose item id omitted from obstacles and supporters.
|
|
8
|
+
* @returns Tagged slots with supporter-top entries before empty-space entries.
|
|
9
|
+
*/
|
|
10
|
+
export function collect_container_slots(container, item, exclude_item_id) {
|
|
11
|
+
const supporter = enumerate_supporter_top_slots(container, item, exclude_item_id);
|
|
12
|
+
const empty = enumerate_empty_space_slots(container, item, exclude_item_id);
|
|
13
|
+
return [
|
|
14
|
+
...tag_slots(supporter, 'supporter_top'),
|
|
15
|
+
...tag_slots(empty, 'empty_space')
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
function tag_slots(slots, slot_kind) {
|
|
19
|
+
return slots.map(position => ({ position, slot_kind }));
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StabilizerContainer, StabilizerItem } from '../validation/contract/stabilizer_domain_schema.js';
|
|
2
|
+
import type { EmptySpaceSlot } from './enumerate_empty_space_slots.js';
|
|
3
|
+
/**
|
|
4
|
+
* Emits one candidate origin per supporter footprint (x, supporter top y, z).
|
|
5
|
+
* @param container - Target container layout.
|
|
6
|
+
* @param item - Loose item dimensions.
|
|
7
|
+
* @param exclude_item_id - Loose item id omitted as a supporter.
|
|
8
|
+
* @returns Slot positions aligned to each supporter origin.
|
|
9
|
+
*/
|
|
10
|
+
export declare function enumerate_supporter_top_slots(container: StabilizerContainer, item: StabilizerItem, exclude_item_id: string): EmptySpaceSlot[];
|
|
11
|
+
//# sourceMappingURL=enumerate_supporter_top_slots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enumerate_supporter_top_slots.d.ts","sourceRoot":"","sources":["../../../src/core/candidates/enumerate_supporter_top_slots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,oDAAoD,CAAA;AAC7G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAItE;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CACzC,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE,cAAc,EACpB,eAAe,EAAE,MAAM,GACxB,cAAc,EAAE,CAgBlB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const CONTAINER_EPSILON = 1e-6;
|
|
2
|
+
/**
|
|
3
|
+
* Emits one candidate origin per supporter footprint (x, supporter top y, z).
|
|
4
|
+
* @param container - Target container layout.
|
|
5
|
+
* @param item - Loose item dimensions.
|
|
6
|
+
* @param exclude_item_id - Loose item id omitted as a supporter.
|
|
7
|
+
* @returns Slot positions aligned to each supporter origin.
|
|
8
|
+
*/
|
|
9
|
+
export function enumerate_supporter_top_slots(container, item, exclude_item_id) {
|
|
10
|
+
const slots = [];
|
|
11
|
+
for (const supporter of container.items) {
|
|
12
|
+
if (supporter.item_id === exclude_item_id) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const slot = supporter_top_slot(supporter);
|
|
16
|
+
if (slot_fits_in_container(container, item, slot)) {
|
|
17
|
+
slots.push(slot);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return slots;
|
|
21
|
+
}
|
|
22
|
+
function supporter_top_slot(supporter) {
|
|
23
|
+
return {
|
|
24
|
+
x: supporter.x,
|
|
25
|
+
y: supporter.y + supporter.height,
|
|
26
|
+
z: supporter.z
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function slot_fits_in_container(container, item, slot) {
|
|
30
|
+
return slot.x >= -CONTAINER_EPSILON &&
|
|
31
|
+
slot.y >= -CONTAINER_EPSILON &&
|
|
32
|
+
slot.z >= -CONTAINER_EPSILON &&
|
|
33
|
+
slot.x + item.width <= container.width + CONTAINER_EPSILON &&
|
|
34
|
+
slot.y + item.height <= container.height + CONTAINER_EPSILON &&
|
|
35
|
+
slot.z + item.depth <= container.length + CONTAINER_EPSILON;
|
|
36
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { StabilizerContainer } from '../validation/contract/stabilizer_domain_schema.js';
|
|
2
|
+
export type CandidateSlotKind = 'empty_space' | 'supporter_top';
|
|
2
3
|
export interface MoveCandidate {
|
|
3
4
|
item_id: string;
|
|
4
5
|
source_container_index: number;
|
|
@@ -8,6 +9,7 @@ export interface MoveCandidate {
|
|
|
8
9
|
y: number;
|
|
9
10
|
z: number;
|
|
10
11
|
};
|
|
12
|
+
slot_kind?: CandidateSlotKind;
|
|
11
13
|
}
|
|
12
14
|
/**
|
|
13
15
|
* Applies a move candidate to containers (mutates arrays in place).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply_move.d.ts","sourceRoot":"","sources":["../../../src/core/move/apply_move.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oDAAoD,CAAA;AAE7F,MAAM,WAAW,aAAa;IAE1B,OAAO,EAAE,MAAM,CAAA;IACf,sBAAsB,EAAE,MAAM,CAAA;IAC9B,sBAAsB,EAAE,MAAM,CAAA;IAC9B,YAAY,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"apply_move.d.ts","sourceRoot":"","sources":["../../../src/core/move/apply_move.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oDAAoD,CAAA;AAE7F,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,eAAe,CAAA;AAE/D,MAAM,WAAW,aAAa;IAE1B,OAAO,EAAE,MAAM,CAAA;IACf,sBAAsB,EAAE,MAAM,CAAA;IAC9B,sBAAsB,EAAE,MAAM,CAAA;IAC9B,YAAY,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACjD,SAAS,CAAC,EAAE,iBAAiB,CAAA;CAChC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACtB,UAAU,EAAE,mBAAmB,EAAE,EACjC,SAAS,EAAE,aAAa,GACzB,IAAI,CAgBN;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,mBAAmB,EAAE,CAGzF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BeamSearchReorder.d.ts","sourceRoot":"","sources":["../../../../src/core/strategies/reorder/BeamSearchReorder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uDAAuD,CAAA;
|
|
1
|
+
{"version":3,"file":"BeamSearchReorder.d.ts","sourceRoot":"","sources":["../../../../src/core/strategies/reorder/BeamSearchReorder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uDAAuD,CAAA;AAahG;;GAEG;AACH,qBAAa,iBAAkB,YAAW,eAAe;IAErD,GAAG,CAAC,OAAO,EAAE,cAAc,GAAG,mBAAmB,EAAE;CAkBtD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { generate_candidates } from '../../candidates/candidate_generator.js';
|
|
2
2
|
import { candidate_context_for_loose } from '../../candidates/build_candidate_context.js';
|
|
3
|
+
import { select_beam_expansion_candidates } from './select_beam_expansion_candidates.js';
|
|
3
4
|
import { apply_move, clone_containers } from '../../move/apply_move.js';
|
|
4
5
|
import { evaluate_trial_layout, evaluation_context_from_reorder } from '../../evaluation/state_evaluator.js';
|
|
5
6
|
import { read_item_score } from '../../adapters/stability_adapter.js';
|
|
@@ -39,7 +40,7 @@ function expand_beam(request) {
|
|
|
39
40
|
function append_beam_branches(beam_context) {
|
|
40
41
|
const { reorder, evaluation, expanded, state, loose } = beam_context;
|
|
41
42
|
const loose_ref = { ...loose, container_index: find_container_index(state.containers, loose.item_id) };
|
|
42
|
-
const candidates = generate_candidates(candidate_context_for_loose(reorder, state.containers, loose_ref))
|
|
43
|
+
const candidates = select_beam_expansion_candidates(generate_candidates(candidate_context_for_loose(reorder, state.containers, loose_ref)), reorder.config.beam_top_k);
|
|
43
44
|
for (const candidate of candidates) {
|
|
44
45
|
const trial = clone_containers(state.containers);
|
|
45
46
|
apply_move(trial, candidate);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MoveCandidate } from '../../move/apply_move.js';
|
|
2
|
+
/**
|
|
3
|
+
* Selects beam expansions: ranked top_k plus every supporter-top slot.
|
|
4
|
+
* @param ranked - Candidates already ranked floor-first.
|
|
5
|
+
* @param top_k - Beam top-k from config.
|
|
6
|
+
* @returns Candidates for trial evaluation.
|
|
7
|
+
*/
|
|
8
|
+
export declare function select_beam_expansion_candidates(ranked: MoveCandidate[], top_k: number): MoveCandidate[];
|
|
9
|
+
//# sourceMappingURL=select_beam_expansion_candidates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select_beam_expansion_candidates.d.ts","sourceRoot":"","sources":["../../../../src/core/strategies/reorder/select_beam_expansion_candidates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAE7D;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC5C,MAAM,EAAE,aAAa,EAAE,EACvB,KAAK,EAAE,MAAM,GACd,aAAa,EAAE,CAKjB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selects beam expansions: ranked top_k plus every supporter-top slot.
|
|
3
|
+
* @param ranked - Candidates already ranked floor-first.
|
|
4
|
+
* @param top_k - Beam top-k from config.
|
|
5
|
+
* @returns Candidates for trial evaluation.
|
|
6
|
+
*/
|
|
7
|
+
export function select_beam_expansion_candidates(ranked, top_k) {
|
|
8
|
+
const leading = ranked.slice(0, top_k);
|
|
9
|
+
const supporter_top = ranked.filter(candidate => candidate.slot_kind === 'supporter_top');
|
|
10
|
+
return unique_move_positions([...leading, ...supporter_top]);
|
|
11
|
+
}
|
|
12
|
+
function unique_move_positions(candidates) {
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
const unique = [];
|
|
15
|
+
for (const candidate of candidates) {
|
|
16
|
+
const key = position_key(candidate);
|
|
17
|
+
if (seen.has(key)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
seen.add(key);
|
|
21
|
+
unique.push(candidate);
|
|
22
|
+
}
|
|
23
|
+
return unique;
|
|
24
|
+
}
|
|
25
|
+
function position_key(candidate) {
|
|
26
|
+
const position = candidate.new_position;
|
|
27
|
+
return `${position.x}:${position.y}:${position.z}:${candidate.target_container_index}`;
|
|
28
|
+
}
|