@jetta/cargo-stabilizer 0.1.0-7 → 0.1.0-9
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 +2 -0
- package/build/core/candidates/candidate_generator.d.ts +1 -1
- package/build/core/candidates/candidate_generator.js +21 -7
- package/build/core/candidates/candidate_validation.d.ts.map +1 -1
- package/build/core/candidates/candidate_validation.js +4 -0
- 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/candidates/is_elevated_on_supporter_origin.d.ts +14 -0
- package/build/core/candidates/is_elevated_on_supporter_origin.d.ts.map +1 -0
- package/build/core/candidates/is_elevated_on_supporter_origin.js +28 -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,8 @@ 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`).
|
|
15
|
+
- Elevated candidates must sit on a supporter `(x, z)` origin so stacked loose items copy the supporter footprint.
|
|
14
16
|
- Public contract exports: `parse_stabilizer_input`, `parse_stabilizer_output`, `safe_parse_stabilizer_input`, `safe_parse_stabilizer_output`, and related domain types.
|
|
15
17
|
|
|
16
18
|
### 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
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"candidate_validation.d.ts","sourceRoot":"","sources":["../../../src/core/candidates/candidate_validation.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"candidate_validation.d.ts","sourceRoot":"","sources":["../../../src/core/candidates/candidate_validation.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AAGxE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,0BAA0B,EACnC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAeT"}
|
|
@@ -3,6 +3,7 @@ import { has_overlap, is_fully_supported, is_inside_container } from '../geometr
|
|
|
3
3
|
import { is_position_in_zone } from '../waypoint/build_waypoint_zones.js';
|
|
4
4
|
import { is_position_in_milkrun_reserved_band } from '../waypoint/milkrun_wall_reservation.js';
|
|
5
5
|
import { resolve_item_waypoint_id } from '../waypoint/validate_waypoint_ids.js';
|
|
6
|
+
import { is_elevated_on_supporter_origin } from './is_elevated_on_supporter_origin.js';
|
|
6
7
|
/**
|
|
7
8
|
* Validates geometry and waypoint constraints for a candidate position.
|
|
8
9
|
* @param context - Candidate generation context.
|
|
@@ -14,6 +15,9 @@ export function is_candidate_valid(context, target_index, position) {
|
|
|
14
15
|
if (!is_candidate_geometry_valid(context, target_index, position)) {
|
|
15
16
|
return false;
|
|
16
17
|
}
|
|
18
|
+
if (!is_elevated_on_supporter_origin(context, target_index, position)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
17
21
|
if (!is_candidate_milkrun_valid(context, target_index, position)) {
|
|
18
22
|
return false;
|
|
19
23
|
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CandidateGenerationContext } from './candidate_context.js';
|
|
2
|
+
/**
|
|
3
|
+
* Floor candidates stay free; elevated ones must copy a supporter (x, z) origin.
|
|
4
|
+
* @param context - Candidate generation context.
|
|
5
|
+
* @param target_index - Target container index.
|
|
6
|
+
* @param position - Candidate position.
|
|
7
|
+
* @returns True when the candidate is on the floor or on a supporter origin.
|
|
8
|
+
*/
|
|
9
|
+
export declare function is_elevated_on_supporter_origin(context: CandidateGenerationContext, target_index: number, position: {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
z: number;
|
|
13
|
+
}): boolean;
|
|
14
|
+
//# sourceMappingURL=is_elevated_on_supporter_origin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is_elevated_on_supporter_origin.d.ts","sourceRoot":"","sources":["../../../src/core/candidates/is_elevated_on_supporter_origin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AAIxE;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC3C,OAAO,EAAE,0BAA0B,EACnC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAQT"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const ORIGIN_EPSILON = 1e-6;
|
|
2
|
+
/**
|
|
3
|
+
* Floor candidates stay free; elevated ones must copy a supporter (x, z) origin.
|
|
4
|
+
* @param context - Candidate generation context.
|
|
5
|
+
* @param target_index - Target container index.
|
|
6
|
+
* @param position - Candidate position.
|
|
7
|
+
* @returns True when the candidate is on the floor or on a supporter origin.
|
|
8
|
+
*/
|
|
9
|
+
export function is_elevated_on_supporter_origin(context, target_index, position) {
|
|
10
|
+
if (position.y <= ORIGIN_EPSILON) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
const items = context.containers[target_index].items;
|
|
14
|
+
return items.some(item => matches_supporter_origin(item, context.loose.item_id, position));
|
|
15
|
+
}
|
|
16
|
+
function matches_supporter_origin(item, exclude_item_id, position) {
|
|
17
|
+
if (item.item_id === exclude_item_id) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return is_same_origin(item, position) && is_supporter_top(item, position.y);
|
|
21
|
+
}
|
|
22
|
+
function is_same_origin(item, position) {
|
|
23
|
+
return Math.abs(item.x - position.x) <= ORIGIN_EPSILON
|
|
24
|
+
&& Math.abs(item.z - position.z) <= ORIGIN_EPSILON;
|
|
25
|
+
}
|
|
26
|
+
function is_supporter_top(item, candidate_y) {
|
|
27
|
+
return Math.abs(item.y + item.height - candidate_y) <= ORIGIN_EPSILON;
|
|
28
|
+
}
|
|
@@ -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
|
+
}
|