@jetta/blocks-allocator 0.0.0-stage → 0.1.0-0
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/README.md +103 -2
- package/package.json +67 -5
- package/src/Allocation_Attempt.js +135 -0
- package/src/Allocation_Error_Handler.js +69 -0
- package/src/Allocation_Flow.js +162 -0
- package/src/Allocation_Optimization/Allocation_LP.js +150 -0
- package/src/Allocation_Optimization/Block_Allocator.js +129 -0
- package/src/Allocation_Optimization/Block_Layer_Order.js +50 -0
- package/src/Allocation_Optimization/Block_Potential_Weight.js +54 -0
- package/src/Allocation_Optimization/Chosen_Blocks_Stock_Cap.js +82 -0
- package/src/Allocation_Optimization/block_builder/Allocation_Item_Creator.js +37 -0
- package/src/Allocation_Optimization/block_builder/Block_Item_List_Validator.js +18 -0
- package/src/Allocation_Optimization/block_builder/Block_Wall_Builder.js +303 -0
- package/src/Allocation_Optimization/block_builder/Blocks_Builder.js +40 -0
- package/src/Allocation_Optimization/block_builder/Next_Block_Position.js +33 -0
- package/src/Allocation_Optimization/block_builder/Slot_Item_Assigner.js +45 -0
- package/src/Allocation_Optimization/block_builder/Stacking_Validation.js +30 -0
- package/src/Allocation_Optimization/block_builder/assert_tie_ratio_block_matches_orientation_below.js +44 -0
- package/src/Allocation_Optimization/block_builder/block_shape_stock.js +129 -0
- package/src/Allocation_Optimization/block_builder/exceptions/Empty_Block_Item_List_Exception.js +21 -0
- package/src/Allocation_Optimization/block_builder/exceptions/Invalid_Stacking_Exception.js +14 -0
- package/src/Allocation_Optimization/block_builder/exceptions/No_Suitable_Item_Exception.js +16 -0
- package/src/Allocation_Optimization/block_builder/exceptions/Restricted_Block_Exception.js +21 -0
- package/src/Allocation_Optimization/block_builder/should_omit_block_group_id.js +29 -0
- package/src/Allocation_Optimization/block_builder/snap_elevated_block_wall_items.js +34 -0
- package/src/Allocation_Optimization/block_builder/stacking_rules_input.js +52 -0
- package/src/Allocation_Optimization/cap_chosen_blocks_by_shape_stock.js +110 -0
- package/src/Allocation_Optimization/density_groups/Adaptive_Density_Group_Preparer.js +21 -0
- package/src/Allocation_Optimization/density_groups/Adaptive_Density_Group_Selector.js +55 -0
- package/src/Allocation_Optimization/density_groups/Adaptive_Density_Group_Threshold_Resolver.js +28 -0
- package/src/Allocation_Optimization/density_groups/Adaptive_Density_Group_Thresholds.js +23 -0
- package/src/Allocation_Optimization/density_groups/Container_Utilization.js +67 -0
- package/src/Allocation_Optimization/density_groups/Density_Group_Partitioner.js +74 -0
- package/src/Allocation_Optimization/density_groups/Density_Group_Scheduler.js +168 -0
- package/src/Allocation_Optimization/density_groups/Density_Group_Stock.js +49 -0
- package/src/Allocation_Optimization/density_groups/Density_Groups_Strategy.js +26 -0
- package/src/Allocation_Optimization/density_groups/Item_Density_Calculator.js +20 -0
- package/src/Allocation_Optimization/density_groups/Lock_Weight_Ahead_Release.js +75 -0
- package/src/Allocation_Optimization/exceptions/Invalid_Item_Amount_Exception.js +17 -0
- package/src/Allocation_Optimization/exceptions/No_Valid_Allocation_Exception.js +14 -0
- package/src/Allocation_Optimization/exceptions/Optimization_Infeasible_Exception.js +14 -0
- package/src/Allocation_Optimization/functions/Measure_Reader.js +20 -0
- package/src/Allocation_Optimization/functions/Weight_Getter/Measure_Cobination_Mode.js +25 -0
- package/src/Allocation_Optimization/functions/Weight_Getter/Measure_Cobination_Strategies.js +8 -0
- package/src/Allocation_Optimization/functions/Weight_Getter/Measure_Combination_Mode_Checkers.js +70 -0
- package/src/Allocation_Optimization/functions/Weight_Getter/Translation.js +22 -0
- package/src/Allocation_Optimization/functions/Weight_Getter/Variable_Weight_Getter.js +85 -0
- package/src/Allocation_Optimization/functions/Weight_Getter/constants.js +16 -0
- package/src/Allocation_Optimization/functions/measure_to_optimize.js +6 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/Capacity_Bias_Item_Order.js +76 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/Choose_Item_Heuristic_Context.js +63 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/Item_Chooser.js +159 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/Item_For_Slot_Chooser.js +49 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/Slot_Compatible_Items_Finder.js +88 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/Slots_Items_Assigner.js +182 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/Stack_Slot_Calculator.js +87 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/Weight_Slot_Distribution.js +72 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/exceptions/Empty_Slot_Exception.js +17 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/exceptions/Item_Taller_Than_Limit_Exception.js +21 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/exceptions/No_Available_Items_Exception.js +14 -0
- package/src/Allocation_Optimization/item_consumption_heuristic/exceptions/No_Slots_For_Items_Exception.js +14 -0
- package/src/Allocation_Optimization/lp_model/Block_Weight_Calculator.js +31 -0
- package/src/Allocation_Optimization/lp_model/LP_Data_Processor.js +42 -0
- package/src/Allocation_Optimization/lp_model/LP_Item_Slot_Assignment.js +93 -0
- package/src/Allocation_Optimization/lp_model/LP_Result_Mapper.js +47 -0
- package/src/Allocation_Optimization/lp_model/model_builder/Dimension_Range_Helper.js +49 -0
- package/src/Allocation_Optimization/lp_model/model_builder/Item_Assignment_Variables.js +133 -0
- package/src/Allocation_Optimization/lp_model/model_builder/LP_Model_Builder.js +132 -0
- package/src/Allocation_Optimization/lp_model/model_builder/exceptions/Missing_Item_Stock_Exception.js +18 -0
- package/src/Allocation_Optimization/lp_model/model_builder/goal_function/Goal_Function_Creator.js +83 -0
- package/src/Allocation_Optimization/lp_model/model_builder/item_dimension_hashes.js +31 -0
- package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Block_Item_Amount_Restriction.js +53 -0
- package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Coherence_Restriction.js +65 -0
- package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Container_Supported_Weight_Restriction.js +42 -0
- package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Relational_Exact_Pass_Amount_Restriction.js +62 -0
- package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Relational_Group_Restriction.js +97 -0
- package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Single_Item_Type_Restriction.js +79 -0
- package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Space_Restriction.js +47 -0
- package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Unavailable_Block_Restriction.js +27 -0
- package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Uniform_Block_Measure_Restriction.js +92 -0
- package/src/Allocation_Optimization/next_group_id_after_preloaded.js +30 -0
- package/src/Allocation_Optimization/preferential_blocks/Preferential_Block_Identifier.js +74 -0
- package/src/Allocation_Optimization/preferential_blocks/key_item/Key_Item_Mapper.js +49 -0
- package/src/Allocation_Optimization/preferential_blocks/key_item/rules/Almost_Unique_Item.js +31 -0
- package/src/Allocation_Optimization/preferential_blocks/key_item/rules/Cant_Stack_It_Self.js +68 -0
- package/src/Allocation_Optimization/preferential_blocks/key_item/rules/Rule_Interface.js +26 -0
- package/src/Allocation_Optimization/tie_ratio/Tie_Ratio_Intercalation_State.js +49 -0
- package/src/Allocation_Optimization/tie_ratio/Tie_Ratio_Orientation_Filter.js +33 -0
- package/src/Allocation_Optimization/tie_ratio/Tie_Ratio_Vertical_Stack_Filter.js +20 -0
- package/src/Allocation_Optimization/tie_ratio/collect_tie_ratio_orientations_below_footprint.js +64 -0
- package/src/Allocation_Optimization/tie_ratio/filter_blocks_by_orientation.js +17 -0
- package/src/Allocation_Optimization/tie_ratio/find_orientation_below_space.js +77 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/allocated_item_penetrates_any.js +31 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/apply_loose_placement_to_allocated_item.js +94 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/axis_overlap_length.js +16 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/block_local_origin.js +18 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/box_fits_inside_container.js +39 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/build_allocated_item_at_placement.js +18 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/build_placement_on_generic_supporter.js +64 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/build_slot_grid_from_cluster.js +66 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/compare_group_ids.js +20 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/container_with_pending_wall_items.js +26 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/empty_space_is_on_floor.js +16 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/finalize_loose_item_placement.js +58 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/find_best_generic_supporter_placement.js +58 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/find_next_free_slot_index.js +119 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/find_supporter_directly_below.js +51 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/find_tie_ratio_supporter_cluster.js +57 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/footprint_xz_overlap_area.js +26 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/item_fits_supporter_slot.js +22 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/loose_footprint_region_from_options.js +24 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/loose_item_fits_inside_container.js +21 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/loose_item_has_geometric_support.js +21 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/loose_on_block_slot_state.js +88 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/placement_coords_fit_inside_container.js +34 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/read_empilhar_area_igual_from_allocation_item.js +12 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/realigned_loose_geometry_gates.js +25 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/resolve_loose_on_generic_supporter.js +65 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/resolve_loose_placement_position.js +68 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/resolve_placement_y_at_slot.js +45 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/resolve_without_tie_ratio_cluster.js +79 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/select_tie_ratio_slot_placement.js +84 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/slot_footprint_collision.js +105 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/tie_ratio_cluster_selection.js +119 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/tie_ratio_footprint_overlap.js +56 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/tie_ratio_placement_plane.js +109 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/tie_ratio_supporter_predicate.js +23 -0
- package/src/Allocation_Optimization/tie_ratio/loose_on_block/try_tie_ratio_slot_placement.js +62 -0
- package/src/Allocation_Optimization/tie_ratio/snap_stacked_items_to_floor_footprints.js +138 -0
- package/src/Allocation_Optimization/tie_ratio/supporters_by_top_y_index.js +78 -0
- package/src/Allocation_Optimization/tie_ratio/tie_ratio_orientation_below_empty_space.js +89 -0
- package/src/Allocation_Optimization/tie_ratio/tie_ratio_orientation_from_group.js +48 -0
- package/src/Block_Management.js +34 -0
- package/src/Blocks_Preparation/Cube_Map_Function.js +27 -0
- package/src/Blocks_Wall_Allocation.js +3 -0
- package/src/IO/Answer_Status.js +4 -0
- package/src/IO/Output_Builder.js +35 -0
- package/src/IO/count_allocated_items.js +31 -0
- package/src/IO/create_error_response.js +62 -0
- package/src/IO/format_allocation_error_message.js +25 -0
- package/src/Item_Continuation_Lock.js +129 -0
- package/src/Item_Picking_Continuity.js +41 -0
- package/src/allocation_flow/chooser_session_state.js +21 -0
- package/src/allocation_flow/compound_probe_fallback.js +17 -0
- package/src/allocation_flow/container_remaining_capacity.js +23 -0
- package/src/allocation_flow/density_group_item_filter.js +31 -0
- package/src/allocation_flow/effective_item_fingerprint.js +14 -0
- package/src/allocation_flow/item_continuation_lock_gate.js +38 -0
- package/src/allocation_flow/no_space_left_recovery.js +48 -0
- package/src/allocation_flow/run_allocation_iteration.js +155 -0
- package/src/allocation_flow/space_skip_state.js +91 -0
- package/src/allocation_flow/try_no_space_left_recovery.js +50 -0
- package/src/exceptions/Invalid_Parameter_Exception.js +17 -0
- package/src/exceptions/Relational_Allocation_Incomplete_Exception.js +24 -0
- package/src/exceptions/Relational_Colocation_Violation_Exception.js +23 -0
- package/src/exceptions/Relational_Config_Mismatch_Exception.js +17 -0
- package/src/exceptions/There_Is_No_Block_Options_To_Allocate_Exception.js +14 -0
- package/src/index.js +6 -0
- package/src/input_preparation/Block_Formatter.js +179 -0
- package/src/input_preparation/Input_Creator.js +76 -0
- package/src/input_preparation/Input_State_Preparation.js +47 -0
- package/src/input_preparation/State_Builder.js +27 -0
- package/src/input_preparation/block_formatter/align_flush_axis_config.js +36 -0
- package/src/input_preparation/block_formatter/align_flush_axis_single_round.js +112 -0
- package/src/input_preparation/block_formatter/align_flush_stacked_slots.js +67 -0
- package/src/input_preparation/block_formatter/overlapped_slots.js +24 -0
- package/src/input_preparation/block_formatter/parallelepiped_shell.js +38 -0
- package/src/input_preparation/block_formatter/rectangle_coverage.js +112 -0
- package/src/input_preparation/block_formatter/shell_face_coverage.js +64 -0
- package/src/input_preparation/block_formatter/shell_snap_convergence.js +104 -0
- package/src/input_preparation/block_preparation/Block_Data_To_Object_Transformer.js +57 -0
- package/src/input_preparation/block_preparation/Block_Module_Name.js +17 -0
- package/src/input_preparation/block_preparation/Blocks_Creator.js +101 -0
- package/src/input_preparation/block_preparation/Blocksmith.js +19 -0
- package/src/input_preparation/block_preparation/block_modules/create_block_candidates.js +41 -0
- package/src/input_preparation/block_preparation/block_modules/manual_blocks.js +10 -0
- package/src/input_preparation/block_preparation/block_modules/module_registry.js +20 -0
- package/src/input_preparation/block_preparation/block_modules/run_creator.js +34 -0
- package/src/input_preparation/block_preparation/block_modules/single_item_blocks.js +12 -0
- package/src/input_preparation/block_preparation/block_modules/spiral_blocks.js +12 -0
- package/src/input_preparation/block_preparation/block_modules/tie_ratio_blocks.js +12 -0
- package/src/input_preparation/block_preparation/block_modules/tower_blocks.js +12 -0
- package/src/input_preparation/block_preparation/exceptions/Failed_To_Create_Block_Exception.js +14 -0
- package/src/input_preparation/block_preparation/exceptions/Failed_To_Retrieve_Block_Exception.js +17 -0
- package/src/input_preparation/block_preparation/exceptions/Missing_Object_Store_Exception.js +10 -0
- package/src/input_preparation/block_preparation/exceptions/No_Blocks_Were_Created_Exception.js +14 -0
- package/src/input_preparation/block_preparation/input/Input_Creator.js +96 -0
- package/src/input_preparation/block_preparation/manual_blocks/Manual_Blocks.js +95 -0
- package/src/input_preparation/build_empty_space_finder_options.js +43 -0
- package/src/input_preparation/item_preparation/Items_Reader.js +27 -0
- package/src/input_preparation/min_extents_from_items.js +29 -0
- package/src/input_preparation/stackability_index/Blocks_Stackability_Index_Calculator.js +58 -0
- package/src/input_preparation/stackability_index/Slots_Stackability_index_Calculator.js +28 -0
- package/src/input_preparation/stackability_index/Stackability_Input_Creator.js +27 -0
- package/src/input_preparation/stackability_index/stackability_index_pop_stack.js +81 -0
- package/src/input_preparation/stacking_constraints/Weight_Stacking_Validation.js +15 -0
- package/src/lp_optimizer_result_status.js +20 -0
- package/src/messages/Allocator_Message.js +42 -0
- package/src/messages/resolve_error_message_entry.js +57 -0
- package/src/models/Allocated_Item.js +136 -0
- package/src/models/Allocation_Item.js +219 -0
- package/src/models/Block.js +198 -0
- package/src/models/Cargo_Profile.js +418 -0
- package/src/models/Preloaded_Allocated_Item.js +132 -0
- package/src/models/Slot.js +67 -0
- package/src/models/Stacking_Rules.js +58 -0
- package/src/models/auxiliaryFunctions/Available_Block_Module_List_Creator.js +9 -0
- package/src/models/auxiliaryFunctions/Measure_Translator.js +24 -0
- package/src/models/auxiliaryFunctions/item_json_reader.js +44 -0
- package/src/models/item_json_reader.js +71 -0
- package/src/models/placed_item_record.js +70 -0
- package/src/models/preloaded_rotation_helpers.js +38 -0
- package/src/models/slots_have_same_measure.js +45 -0
- package/src/models/transport/Container.js +162 -0
- package/src/models/transport/Transport.js +62 -0
- package/src/models/transport/build_stacking_feasibility_checker.js +64 -0
- package/src/models/transport/container_stacking_checkpoint.js +42 -0
- package/src/models/transport/factory/Container_Factory.js +46 -0
- package/src/models/transport/factory/Corner_Casting_Factory.js +62 -0
- package/src/models/transport/factory/Previously_Allocated_Item_Factory.js +28 -0
- package/src/models/transport/factory/Transport_Factory.js +13 -0
- package/src/models/transport/items_for_empty_space_finder.js +91 -0
- package/src/models/transport/resolve_container_stacking_inputs.js +23 -0
- package/src/models/transport/stacking_input_from_wire.js +58 -0
- package/src/optimizer_connection_errors.js +50 -0
- package/src/relational/Relational_Error_Codes.js +7 -0
- package/src/relational/finalize_relational_allocation.js +20 -0
- package/src/relational/has_relational_items.js +11 -0
- package/src/relational/is_relational_error_code.js +15 -0
- package/src/relational/resolve_relational_container_sequences.js +29 -0
- package/src/run_core_allocation.js +118 -0
- package/src/space_and_block_chooser/Space_And_Blocks_Chooser.js +115 -0
- package/src/space_and_block_chooser/blocks_filters/Block_Filter_Interface.js +19 -0
- package/src/space_and_block_chooser/blocks_filters/Filter_Runner.js +46 -0
- package/src/space_and_block_chooser/blocks_filters/initial_blocks_filter/Block_With_Overlapped_Slots_Filter.js +14 -0
- package/src/space_and_block_chooser/blocks_filters/initial_blocks_filter/Initial_Blocks_Filter_List.js +19 -0
- package/src/space_and_block_chooser/blocks_filters/pos_selection_filters/Blocks_Bigger_Than_Space_Filter.js +17 -0
- package/src/space_and_block_chooser/blocks_filters/pos_selection_filters/Post_Selection_Filter_List.js +9 -0
- package/src/space_and_block_chooser/blocks_filters/pre_selection_filter/Insuficient_Items_Filter.js +81 -0
- package/src/space_and_block_chooser/blocks_filters/pre_selection_filter/Pre_Selection_Filter_List.js +8 -0
- package/src/space_and_block_chooser/blocks_filters/pre_selection_filter/max_tower_height/Blocks_Lower_Than_Max_Tower_Height.js +23 -0
- package/src/space_and_block_chooser/blocks_filters/pre_selection_filter/max_tower_height/Max_Tower_Height.js +82 -0
- package/src/space_and_block_chooser/build_allocated_item_snapshots.js +19 -0
- package/src/space_and_block_chooser/compound_first_empty_space_branch.js +61 -0
- package/src/space_and_block_chooser/compound_first_with_leftover_fill.js +142 -0
- package/src/space_and_block_chooser/compound_first_without_leftover_fill.js +56 -0
- package/src/space_and_block_chooser/empty_spaces_where_post_selection_keeps_blocks.js +83 -0
- package/src/space_and_block_chooser/exceptions/Invalid_Space_To_Allocate_Exception.js +14 -0
- package/src/space_and_block_chooser/leftover_space_memory.js +113 -0
- package/src/space_and_block_chooser/leftover_unitary_blocks.js +153 -0
- package/src/space_and_block_chooser/leftover_unitary_empty_spaces.js +135 -0
- package/src/space_and_block_chooser/probe_set_pool.js +35 -0
- package/src/space_and_block_chooser/run_space_and_block_selection_attempt.js +88 -0
- package/src/tools/Array_Validator.js +6 -0
- package/src/tools/Clone.js +27 -0
- package/src/tools/Hash.js +8 -0
- package/src/tools/Rounder.js +5 -0
- package/src/tools/String_To_Boolean.js +12 -0
- package/src/tools/cargo_profile/Cargo_Profile_Field_Value_Resolver.js +44 -0
- package/src/tools/compact_items_with_stock.js +9 -0
- package/src/tools/mm_to_allocation_domain.js +14 -0
- package/src/tracing/Allocation_Tracer.js +52 -0
- package/src/tracing/Trace_Context.js +18 -0
- package/src/tracing/trace_outcome.js +18 -0
- package/src/tracing/traced_step.js +57 -0
- package/src/validation/Item_Continuation_Lock_Flag.js +52 -0
- package/src/validation/Item_Validation.js +29 -0
- package/src/validation/Relational_Colocation_Validator.js +60 -0
- package/src/validation/Relational_Completeness_Validator.js +146 -0
- package/src/validation/Relational_Continuation_Lock_Validation.js +37 -0
- package/src/validation/Relational_Proportional_Normalizer.js +194 -0
- package/src/validation/Validation.js +9 -0
- package/src/validation/Validation_Runner.js +20 -0
- package/src/validation/exceptions/Invalid_Block_Module_Config_Exception.js +14 -0
- package/src/validation/exceptions/Invalid_Input_Exception.js +14 -0
- package/src/validation/exceptions/Invalid_Input_Type_Exception.js +14 -0
- package/src/validation/schemas/allocated_item_schema.js +18 -0
- package/src/validation/schemas/allocation_request_schema.js +178 -0
- package/src/validation/schemas/container_row_schema.js +16 -0
- package/src/validation/schemas/item_schema.js +60 -0
- package/src/validation/schemas/transport_env_schema.js +19 -0
- package/src/validation/validate_block_module_config.js +147 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
const No_Available_Items_Exception = require('./exceptions/No_Available_Items_Exception')
|
|
2
|
+
const No_Slots_For_Items_Exception = require('./exceptions/No_Slots_For_Items_Exception')
|
|
3
|
+
const Cargo_Profile = require('../../models/Cargo_Profile')
|
|
4
|
+
const No_Suitable_Item_Exception = require('../block_builder/exceptions/No_Suitable_Item_Exception')
|
|
5
|
+
const { ALLOCATOR_MESSAGE } = require('../../messages/Allocator_Message')
|
|
6
|
+
const Allocated_Item = require('../../models/Allocated_Item')
|
|
7
|
+
const { distribute_items_by_weight_range } = require('./Weight_Slot_Distribution')
|
|
8
|
+
const {
|
|
9
|
+
resolve_choose_item_heuristic_context,
|
|
10
|
+
format_slot_label_for_exception
|
|
11
|
+
} = require('./Choose_Item_Heuristic_Context')
|
|
12
|
+
const {
|
|
13
|
+
calculate_total_stack_slots,
|
|
14
|
+
sort_stacking_slots_by_proximity
|
|
15
|
+
} = require('./Stack_Slot_Calculator')
|
|
16
|
+
const { order_items_by_capacity_bias } = require('./Capacity_Bias_Item_Order')
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Chooses an item from available items by distributing them into stacking slots by weight
|
|
20
|
+
* and returning the item in the slot closest to the block slot position.
|
|
21
|
+
* @param {object} data - Input bag.
|
|
22
|
+
* @param {object} [data.slot] - Slot with get_y() and get_height() (production).
|
|
23
|
+
* @param {object} [data.block_slot] - Legacy alias for slot (tests).
|
|
24
|
+
* @param {object} [data.container] - Container with get_height() and is_a_valid_stacking().
|
|
25
|
+
* @param {number} [data.height_limit] - Used with a stub container when data.container is absent.
|
|
26
|
+
* @param {object} [data.item_position] - { x, y, z }; defaults to origin when absent.
|
|
27
|
+
* @param {object[]} data.item_list - Items with get_weight().
|
|
28
|
+
* @param {number} [data.qty_of_slots] - Required when the heuristic runs.
|
|
29
|
+
* @param {string} [data.previous_chosen_item_id] - Optional previous choice.
|
|
30
|
+
* @returns {object} The chosen item.
|
|
31
|
+
* @throws {Item_Bigger_Than_Limit} When item height exceeds height_limit.
|
|
32
|
+
* @throws {Empty_Slot_Error} When no stacking slots have items.
|
|
33
|
+
* @throws {No_Available_Items_Exception} When item_list is empty.
|
|
34
|
+
* @throws {No_Suitable_Item_Exception} When no item passes stacking in any weight band.
|
|
35
|
+
*/
|
|
36
|
+
module.exports = function choose_item(data)
|
|
37
|
+
{
|
|
38
|
+
const { item_list, previous_chosen_item_id } = data
|
|
39
|
+
if (item_list.length === 0)
|
|
40
|
+
{
|
|
41
|
+
throw new No_Available_Items_Exception()
|
|
42
|
+
}
|
|
43
|
+
const is_to_prefer_same_id = data.block.get_slot_list().length > 0 && previous_chosen_item_id !== undefined && Cargo_Profile.prefer_block_with_same_item()
|
|
44
|
+
return is_to_prefer_same_id ? prefer_same_id(data) : choose_item_with_heuristic(data)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function prefer_same_id(data)
|
|
48
|
+
{
|
|
49
|
+
const { container, item_list, previous_chosen_item_id, item_position } = data
|
|
50
|
+
const allocation_item = item_list.find(item => item.get_id() === previous_chosen_item_id)
|
|
51
|
+
if (allocation_item)
|
|
52
|
+
{
|
|
53
|
+
const result = is_stacking_valid(container, allocation_item, item_position, data.block)
|
|
54
|
+
if (result.is_valid)
|
|
55
|
+
{
|
|
56
|
+
return result.allocated_item
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return choose_item_with_heuristic(data)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Heuristic path: weight bands, proximity-ordered bands, stacking validation per candidate.
|
|
65
|
+
* @param {object} data - Input bag (see choose_item).
|
|
66
|
+
* @returns {object} Chosen item.
|
|
67
|
+
*/
|
|
68
|
+
function choose_item_with_heuristic(data)
|
|
69
|
+
{
|
|
70
|
+
const { slot, container, item_position } = resolve_choose_item_heuristic_context(data)
|
|
71
|
+
const { item_list, qty_of_slots } = data
|
|
72
|
+
const total_slots = calculate_total_stack_slots(container.get_height(), slot)
|
|
73
|
+
const stacking_slots = distribute_items_by_weight_range(item_list, total_slots)
|
|
74
|
+
const ordered_bands = sort_stacking_slots_by_proximity(
|
|
75
|
+
stacking_slots,
|
|
76
|
+
slot.get_y(),
|
|
77
|
+
slot.get_height()
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
for (const band of ordered_bands)
|
|
81
|
+
{
|
|
82
|
+
const candidate_items = band.items
|
|
83
|
+
while (candidate_items.length > 0)
|
|
84
|
+
{
|
|
85
|
+
const allocation_item = get_item(candidate_items, qty_of_slots, container)
|
|
86
|
+
const result = is_stacking_valid(container, allocation_item, item_position, data.block)
|
|
87
|
+
if (result.is_valid)
|
|
88
|
+
{
|
|
89
|
+
return result.allocated_item
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
remove_item_from_candidate_list(candidate_items, allocation_item)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const slot_label = format_slot_label_for_exception(slot)
|
|
97
|
+
throw new No_Suitable_Item_Exception(ALLOCATOR_MESSAGE.NO_SUITABLE_ITEM, [slot_label])
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function is_stacking_valid(container, allocation_item, item_position, block)
|
|
101
|
+
{
|
|
102
|
+
const allocated_item = new Allocated_Item(
|
|
103
|
+
allocation_item,
|
|
104
|
+
item_position.x,
|
|
105
|
+
item_position.y,
|
|
106
|
+
item_position.z
|
|
107
|
+
)
|
|
108
|
+
if (should_defer_loose_on_block_stacking_validation(block))
|
|
109
|
+
{
|
|
110
|
+
return {
|
|
111
|
+
is_valid: true,
|
|
112
|
+
allocated_item
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const is_valid = container.is_a_valid_stacking(allocated_item)
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
is_valid,
|
|
119
|
+
allocated_item
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function should_defer_loose_on_block_stacking_validation(block)
|
|
124
|
+
{
|
|
125
|
+
return Cargo_Profile.stack_loose_on_tie_ratio_blocks()
|
|
126
|
+
&& block?.get_slot_list?.().length === 1
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function remove_item_from_candidate_list(candidate_item_list, allocation_item)
|
|
130
|
+
{
|
|
131
|
+
const index = candidate_item_list.indexOf(allocation_item)
|
|
132
|
+
if (index > -1)
|
|
133
|
+
{
|
|
134
|
+
candidate_item_list.splice(index, 1)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function get_item(item_list, qty_of_slots, container)
|
|
139
|
+
{
|
|
140
|
+
if (qty_of_slots === undefined)
|
|
141
|
+
{
|
|
142
|
+
throw new No_Slots_For_Items_Exception()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (item_list.length === 0)
|
|
146
|
+
{
|
|
147
|
+
throw new No_Available_Items_Exception()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const ordered_item_list = order_items_by_capacity_bias(item_list, container)
|
|
151
|
+
const preferable_item_list = ordered_item_list.filter(item => item.get_amount() >= qty_of_slots)
|
|
152
|
+
|
|
153
|
+
if (preferable_item_list.length > 0)
|
|
154
|
+
{
|
|
155
|
+
return preferable_item_list[0]
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return ordered_item_list[0]
|
|
159
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const choose_item = require('./Item_Chooser')
|
|
2
|
+
const get_available_items_for_slot = require('./Slot_Compatible_Items_Finder')
|
|
3
|
+
const { order_items_by_capacity_bias } = require('./Capacity_Bias_Item_Order')
|
|
4
|
+
const { ge } = require('@jetta/number-compare')
|
|
5
|
+
const No_Suitable_Item_Exception = require('../block_builder/exceptions/No_Suitable_Item_Exception')
|
|
6
|
+
const { ALLOCATOR_MESSAGE } = require('../../messages/Allocator_Message')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Chooses an item suitable for the given slot from available items, respecting weight and stacking.
|
|
10
|
+
* @param {object} data - Container, block, slot, weight, and item maps.
|
|
11
|
+
* @returns {object} The chosen item for the slot.
|
|
12
|
+
* @throws {No_Suitable_Item_Exception} When no item fits the slot or stacking rules.
|
|
13
|
+
*/
|
|
14
|
+
module.exports = function choose_item_for_slot(data)
|
|
15
|
+
{
|
|
16
|
+
const item_list = get_available_item_list(data)
|
|
17
|
+
return choose_item({ ...data, item_list, height_limit: data.container.get_height() })
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {object} data
|
|
22
|
+
* @returns {object[]}
|
|
23
|
+
*/
|
|
24
|
+
function get_available_item_list(data)
|
|
25
|
+
{
|
|
26
|
+
const { slot, container_supported_weight, item_map, item_amount_map } = data
|
|
27
|
+
const available_items_for_slot = get_available_items_for_slot(slot, item_map, item_amount_map)
|
|
28
|
+
const available_item_list = available_items_for_slot.filter(
|
|
29
|
+
item => item_supports_weight(container_supported_weight, item)
|
|
30
|
+
)
|
|
31
|
+
if (available_item_list.length === 0)
|
|
32
|
+
{
|
|
33
|
+
throw new No_Suitable_Item_Exception(
|
|
34
|
+
ALLOCATOR_MESSAGE.NO_SUITABLE_ITEM,
|
|
35
|
+
[slot.to_string()]
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
return order_items_by_capacity_bias(available_item_list, data.container)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {number} max_weight
|
|
43
|
+
* @param {object} item
|
|
44
|
+
* @returns {boolean}
|
|
45
|
+
*/
|
|
46
|
+
function item_supports_weight(max_weight, item)
|
|
47
|
+
{
|
|
48
|
+
return ge(max_weight, item.get_weight())
|
|
49
|
+
}
|
package/src/Allocation_Optimization/item_consumption_heuristic/Slot_Compatible_Items_Finder.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const { cube_map_function } = require('../../Blocks_Preparation/Cube_Map_Function')
|
|
2
|
+
|
|
3
|
+
const dimension_index_by_item_map = new WeakMap()
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns items that have positive amount and fit the slot (including rotations).
|
|
7
|
+
* Builds a dimension→item index once per `item_map` instance (WeakMap-cached).
|
|
8
|
+
* @param {object} slot - Target slot.
|
|
9
|
+
* @param {object} item_map - Map of item id to item.
|
|
10
|
+
* @param {object} item_amount_map - Map of item to available amount.
|
|
11
|
+
* @returns {Array} List of compatible rotated items.
|
|
12
|
+
*/
|
|
13
|
+
module.exports = function get_available_items_for_slot(slot, item_map, item_amount_map)
|
|
14
|
+
{
|
|
15
|
+
const dimension_index = get_or_build_dimension_index(item_map)
|
|
16
|
+
const candidates = dimension_index.get(cube_map_function(slot)) || []
|
|
17
|
+
const compatible = []
|
|
18
|
+
for (const candidate of candidates)
|
|
19
|
+
{
|
|
20
|
+
const item = item_map[candidate.item_id]
|
|
21
|
+
if (!item || item_amount_map.get_item_amount(item) <= 0)
|
|
22
|
+
{
|
|
23
|
+
continue
|
|
24
|
+
}
|
|
25
|
+
compatible.push(item.copy_rotated(item.get_rotated_item(candidate.rotation)))
|
|
26
|
+
}
|
|
27
|
+
return compatible
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {object} item_map
|
|
32
|
+
* @returns {Map<string, Array<{ item_id: string, rotation: * }>>}
|
|
33
|
+
*/
|
|
34
|
+
function get_or_build_dimension_index(item_map)
|
|
35
|
+
{
|
|
36
|
+
let dimension_index = dimension_index_by_item_map.get(item_map)
|
|
37
|
+
if (dimension_index)
|
|
38
|
+
{
|
|
39
|
+
return dimension_index
|
|
40
|
+
}
|
|
41
|
+
dimension_index = build_dimension_index(item_map)
|
|
42
|
+
dimension_index_by_item_map.set(item_map, dimension_index)
|
|
43
|
+
return dimension_index
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {object} item_map
|
|
48
|
+
* @returns {Map<string, Array<{ item_id: string, rotation: * }>>}
|
|
49
|
+
*/
|
|
50
|
+
function build_dimension_index(item_map)
|
|
51
|
+
{
|
|
52
|
+
const dimension_index = new Map()
|
|
53
|
+
for (const item_id of Object.keys(item_map))
|
|
54
|
+
{
|
|
55
|
+
index_item_rotations(dimension_index, item_map[item_id], item_id)
|
|
56
|
+
}
|
|
57
|
+
return dimension_index
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {Map<string, Array<{ item_id: string, rotation: * }>>} dimension_index
|
|
62
|
+
* @param {object} item
|
|
63
|
+
* @param {string} item_id
|
|
64
|
+
* @returns {void}
|
|
65
|
+
*/
|
|
66
|
+
function index_item_rotations(dimension_index, item, item_id)
|
|
67
|
+
{
|
|
68
|
+
const indexed_dimensions = new Set()
|
|
69
|
+
for (const rotation of item.get_rotations())
|
|
70
|
+
{
|
|
71
|
+
const rotated_item = item.get_rotated_item(rotation)
|
|
72
|
+
const dimension_key = cube_map_function(rotated_item)
|
|
73
|
+
if (indexed_dimensions.has(dimension_key))
|
|
74
|
+
{
|
|
75
|
+
continue
|
|
76
|
+
}
|
|
77
|
+
indexed_dimensions.add(dimension_key)
|
|
78
|
+
const candidates = dimension_index.get(dimension_key)
|
|
79
|
+
if (candidates)
|
|
80
|
+
{
|
|
81
|
+
candidates.push({ item_id, rotation })
|
|
82
|
+
}
|
|
83
|
+
else
|
|
84
|
+
{
|
|
85
|
+
dimension_index.set(dimension_key, [{ item_id, rotation }])
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
const choose_item_for_slot = require('./Item_For_Slot_Chooser')
|
|
2
|
+
const No_Suitable_Item_Exception = require('../block_builder/exceptions/No_Suitable_Item_Exception')
|
|
3
|
+
const { ALLOCATOR_MESSAGE } = require('../../messages/Allocator_Message')
|
|
4
|
+
const Allocated_Item = require('../../models/Allocated_Item')
|
|
5
|
+
const { block_has_sufficient_shape_stock } = require('../block_builder/block_shape_stock')
|
|
6
|
+
const { Logger } = require('@jetta/logger')
|
|
7
|
+
const logger = new Logger('Item Consumption Heuristic')
|
|
8
|
+
const order_slots_by_y = (slot_list) => [...slot_list].sort(compare_slot_y_asc)
|
|
9
|
+
const compare_slot_y_asc = (slot_a, slot_b) => slot_a.get_y() - slot_b.get_y()
|
|
10
|
+
|
|
11
|
+
function build_item_map(item_list)
|
|
12
|
+
{
|
|
13
|
+
const item_map = {}
|
|
14
|
+
for (const item of item_list)
|
|
15
|
+
{
|
|
16
|
+
item_map[item.get_id()] = item
|
|
17
|
+
}
|
|
18
|
+
return item_map
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function process_one_slot(data)
|
|
22
|
+
{
|
|
23
|
+
const allocated_item = choose_item_for_slot(data)
|
|
24
|
+
data.item_amount_map.discount_single_item(allocated_item)
|
|
25
|
+
const next_weight = data.container_supported_weight - allocated_item.get_weight()
|
|
26
|
+
return { allocated_item, next_weight }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Assigns items to block slots using a consumption heuristic (slot order and stacking).
|
|
31
|
+
*/
|
|
32
|
+
class Item_Consumption_Heuristic
|
|
33
|
+
{
|
|
34
|
+
#empty_space
|
|
35
|
+
#item_map = {}
|
|
36
|
+
#item_amount_map
|
|
37
|
+
#container
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {object[]} item_list - Items available for allocation.
|
|
41
|
+
* @param {object} item_amount_map - Tracks remaining amount per item.
|
|
42
|
+
* @param {object} container - Target container.
|
|
43
|
+
*/
|
|
44
|
+
constructor(empty_space, item_list, item_amount_map, container)
|
|
45
|
+
{
|
|
46
|
+
this.#empty_space = empty_space
|
|
47
|
+
this.#item_map = build_item_map(item_list)
|
|
48
|
+
this.#item_amount_map = item_amount_map
|
|
49
|
+
this.#container = container
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Assigns one item per slot of the block, ordered by slot y, updating weight and amounts.
|
|
54
|
+
* @param {object} block - Block whose slots are to be filled.
|
|
55
|
+
* @param {number} container_supported_weight - Supported weight for the layer.
|
|
56
|
+
* @param {object} item_position - Base block position { x, y, z } before per-slot offsets (from space / block placement).
|
|
57
|
+
* @param {string|undefined} picking_continuity_seed - Prior SKU id to prefer on the first slot.
|
|
58
|
+
* @returns {object[]|undefined} Allocated items, or undefined if a non-rethrown error occurred.
|
|
59
|
+
*/
|
|
60
|
+
assign_items_to_slots(block, container_supported_weight, item_position, picking_continuity_seed)
|
|
61
|
+
{
|
|
62
|
+
const slot_count = block.get_slot_list().length
|
|
63
|
+
if (slot_count === 0)
|
|
64
|
+
{
|
|
65
|
+
return []
|
|
66
|
+
}
|
|
67
|
+
if (!block_has_sufficient_shape_stock(block, this.#item_map, this.#item_amount_map))
|
|
68
|
+
{
|
|
69
|
+
throw new No_Suitable_Item_Exception(
|
|
70
|
+
ALLOCATOR_MESSAGE.INSUFFICIENT_SHAPE_STOCK,
|
|
71
|
+
[String(slot_count)]
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
logger.debug(`assigning items to ${slot_count} slot(s)`)
|
|
75
|
+
return this.#assign_items_for_ordered_slots(
|
|
76
|
+
block,
|
|
77
|
+
Number(container_supported_weight),
|
|
78
|
+
item_position,
|
|
79
|
+
picking_continuity_seed
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Assigns specific items to slots using the LP plan (relational co-location path).
|
|
85
|
+
* @param {object} block
|
|
86
|
+
* @param {string[]} slot_item_ids - Item ids per slot (same order as ordered slots).
|
|
87
|
+
* @param {number} container_supported_weight
|
|
88
|
+
* @param {object} item_position
|
|
89
|
+
* @returns {object[]}
|
|
90
|
+
*/
|
|
91
|
+
assign_items_from_plan(block, slot_item_ids, container_supported_weight, item_position)
|
|
92
|
+
{
|
|
93
|
+
const slot_list = order_slots_by_y(block.get_slot_list())
|
|
94
|
+
const allocated_item_list = []
|
|
95
|
+
|
|
96
|
+
for (let index = 0; index < slot_list.length; index++)
|
|
97
|
+
{
|
|
98
|
+
const slot = slot_list[index]
|
|
99
|
+
const item_id = slot_item_ids[index]
|
|
100
|
+
const allocation_item = this.#item_map[item_id]
|
|
101
|
+
if (!allocation_item || allocation_item.get_amount() <= 0)
|
|
102
|
+
{
|
|
103
|
+
throw new No_Suitable_Item_Exception(
|
|
104
|
+
ALLOCATOR_MESSAGE.LP_PLAN_ITEM_UNAVAILABLE,
|
|
105
|
+
[String(item_id), slot.to_string()]
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const current_item_position = this.#update_item_position(item_position, slot)
|
|
110
|
+
const allocated_item = new Allocated_Item(
|
|
111
|
+
allocation_item,
|
|
112
|
+
current_item_position.x,
|
|
113
|
+
current_item_position.y,
|
|
114
|
+
current_item_position.z
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
if (!this.#container.is_a_valid_stacking(allocated_item))
|
|
118
|
+
{
|
|
119
|
+
throw new No_Suitable_Item_Exception(
|
|
120
|
+
ALLOCATOR_MESSAGE.LP_PLAN_ITEM_STACKING_FAILED,
|
|
121
|
+
[String(item_id), slot.to_string()]
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.#item_amount_map.discount_single_item(allocated_item)
|
|
126
|
+
allocated_item_list.push(allocated_item)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
logger.debug(`assigned ${allocated_item_list.length} item(s) from LP plan`)
|
|
130
|
+
return allocated_item_list
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#update_item_position(item_position, slot)
|
|
134
|
+
{
|
|
135
|
+
return {
|
|
136
|
+
x: item_position.x + slot.get_x(),
|
|
137
|
+
y: item_position.y + slot.get_y(),
|
|
138
|
+
z: item_position.z + slot.get_z()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#assign_items_for_ordered_slots(block, initial_weight, starting_item_position, picking_continuity_seed)
|
|
143
|
+
{
|
|
144
|
+
const slot_list = order_slots_by_y(block.get_slot_list())
|
|
145
|
+
const allocated_item_list = new Array(slot_list.length)
|
|
146
|
+
const provisional_amount_map = this.#item_amount_map.copy()
|
|
147
|
+
let current_weight = initial_weight
|
|
148
|
+
let previous_chosen_item_id = picking_continuity_seed ?? undefined
|
|
149
|
+
let qty_of_slots = slot_list.length
|
|
150
|
+
|
|
151
|
+
for (let index = 0; index < slot_list.length; index++)
|
|
152
|
+
{
|
|
153
|
+
const slot = slot_list[index]
|
|
154
|
+
const current_item_position = this.#update_item_position(starting_item_position, slot)
|
|
155
|
+
const result = process_one_slot({
|
|
156
|
+
empty_space: this.#empty_space,
|
|
157
|
+
slot,
|
|
158
|
+
container_supported_weight: current_weight,
|
|
159
|
+
container: this.#container,
|
|
160
|
+
block,
|
|
161
|
+
item_map: this.#item_map,
|
|
162
|
+
item_amount_map: provisional_amount_map,
|
|
163
|
+
previous_chosen_item_id,
|
|
164
|
+
qty_of_slots,
|
|
165
|
+
item_position: current_item_position
|
|
166
|
+
})
|
|
167
|
+
allocated_item_list[index] = result.allocated_item
|
|
168
|
+
current_weight = result.next_weight
|
|
169
|
+
previous_chosen_item_id = result.allocated_item.get_id()
|
|
170
|
+
qty_of_slots--
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
for (const allocated_item of allocated_item_list)
|
|
174
|
+
{
|
|
175
|
+
this.#item_amount_map.discount_single_item(allocated_item)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return allocated_item_list
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = Item_Consumption_Heuristic
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const Empty_Slot_Error = require('./exceptions/Empty_Slot_Exception')
|
|
2
|
+
const Item_Bigger_Than_Limit = require('./exceptions/Item_Taller_Than_Limit_Exception')
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {number} height_limit - Maximum stack height.
|
|
6
|
+
* @param {object} item - With get_height().
|
|
7
|
+
* @returns {number} Number of vertical slots that fit.
|
|
8
|
+
* @throws {Item_Bigger_Than_Limit} When item height exceeds height_limit.
|
|
9
|
+
*/
|
|
10
|
+
function calculate_total_stack_slots(height_limit, item)
|
|
11
|
+
{
|
|
12
|
+
const total_slots = Math.floor(height_limit / item.get_height())
|
|
13
|
+
if (total_slots === 0)
|
|
14
|
+
{
|
|
15
|
+
throw new Item_Bigger_Than_Limit(height_limit, item)
|
|
16
|
+
}
|
|
17
|
+
return total_slots
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {object[]} slots - Slots with vertical_index and items.
|
|
22
|
+
* @param {number} target_y - Target y position.
|
|
23
|
+
* @param {number} item_height - Height per slot.
|
|
24
|
+
* @returns {object} Slot closest to target_y.
|
|
25
|
+
* @throws {Empty_Slot_Error} When slots is empty.
|
|
26
|
+
*/
|
|
27
|
+
function find_closest_slot_to_position(slots, target_y, item_height)
|
|
28
|
+
{
|
|
29
|
+
const first_slot = slots[0]
|
|
30
|
+
if (!first_slot)
|
|
31
|
+
{
|
|
32
|
+
throw new Empty_Slot_Error(target_y)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let closest_slot = first_slot
|
|
36
|
+
let smallest_difference = Infinity
|
|
37
|
+
|
|
38
|
+
for (const slot of slots)
|
|
39
|
+
{
|
|
40
|
+
const slot_y = slot.vertical_index * item_height
|
|
41
|
+
const distance = Math.abs(slot_y - target_y)
|
|
42
|
+
if (distance < smallest_difference)
|
|
43
|
+
{
|
|
44
|
+
smallest_difference = distance
|
|
45
|
+
closest_slot = slot
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return closest_slot
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Non-empty stacking slots ordered by vertical distance to target_y (ties keep input order).
|
|
54
|
+
* @param {object[]} slots - Slots with vertical_index and items.
|
|
55
|
+
* @param {number} target_y - Target y position.
|
|
56
|
+
* @param {number} item_height - Height per slot.
|
|
57
|
+
* @returns {object[]} Same slot objects as input, sorted by proximity.
|
|
58
|
+
* @throws {Empty_Slot_Error} When slots is empty.
|
|
59
|
+
*/
|
|
60
|
+
function sort_stacking_slots_by_proximity(slots, target_y, item_height)
|
|
61
|
+
{
|
|
62
|
+
const first_slot = slots[0]
|
|
63
|
+
if (!first_slot)
|
|
64
|
+
{
|
|
65
|
+
throw new Empty_Slot_Error(target_y)
|
|
66
|
+
}
|
|
67
|
+
const with_meta = slots.map((slot, index) => ({
|
|
68
|
+
slot,
|
|
69
|
+
distance: Math.abs(slot.vertical_index * item_height - target_y),
|
|
70
|
+
index
|
|
71
|
+
}))
|
|
72
|
+
with_meta.sort((a, b) =>
|
|
73
|
+
{
|
|
74
|
+
if (a.distance !== b.distance)
|
|
75
|
+
{
|
|
76
|
+
return a.distance - b.distance
|
|
77
|
+
}
|
|
78
|
+
return a.index - b.index
|
|
79
|
+
})
|
|
80
|
+
return with_meta.map((entry) => entry.slot)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = {
|
|
84
|
+
calculate_total_stack_slots,
|
|
85
|
+
find_closest_slot_to_position,
|
|
86
|
+
sort_stacking_slots_by_proximity
|
|
87
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distributes items into stacking slots by normalized weight (heavier toward bottom).
|
|
3
|
+
* @param {object[]} items - Items with get_weight().
|
|
4
|
+
* @param {number} total_slots - Number of vertical slots.
|
|
5
|
+
* @returns {object[]} Slots with vertical_index and items (non-empty only).
|
|
6
|
+
*/
|
|
7
|
+
function distribute_items_by_weight_range(items, total_slots)
|
|
8
|
+
{
|
|
9
|
+
const normalized_weights = normalize_weights(items)
|
|
10
|
+
const slots = initialize_slots(total_slots)
|
|
11
|
+
|
|
12
|
+
for (let index = 0; index < items.length; index++)
|
|
13
|
+
{
|
|
14
|
+
const relative_weight = normalized_weights[index]
|
|
15
|
+
const slot_index = map_weight_to_slot_index(relative_weight, total_slots)
|
|
16
|
+
slots[slot_index].items.push(items[index])
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return slots.filter(slot_has_items)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function slot_has_items(slot)
|
|
23
|
+
{
|
|
24
|
+
return slot.items.length > 0
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {object[]} item_list - Items with get_weight().
|
|
29
|
+
* @returns {number[]} Weights normalized to [0, 1] per item.
|
|
30
|
+
*/
|
|
31
|
+
function normalize_weights(item_list)
|
|
32
|
+
{
|
|
33
|
+
const weights = item_list.map(get_item_weight)
|
|
34
|
+
const min = Math.min(...weights)
|
|
35
|
+
const max = Math.max(...weights)
|
|
36
|
+
const delta = max - min || 1e-6
|
|
37
|
+
const result = new Array(item_list.length)
|
|
38
|
+
for (let index = 0; index < item_list.length; index++)
|
|
39
|
+
{
|
|
40
|
+
result[index] = normalized_weight(item_list[index], min, delta)
|
|
41
|
+
}
|
|
42
|
+
return result
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function get_item_weight(item)
|
|
46
|
+
{
|
|
47
|
+
return item.get_weight()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function normalized_weight(item, min, delta)
|
|
51
|
+
{
|
|
52
|
+
return (item.get_weight() - min) / delta
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function initialize_slots(count)
|
|
56
|
+
{
|
|
57
|
+
const slots = new Array(count)
|
|
58
|
+
for (let index = 0; index < count; index++)
|
|
59
|
+
{
|
|
60
|
+
slots[index] = { vertical_index: index, items: [] }
|
|
61
|
+
}
|
|
62
|
+
return slots
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function map_weight_to_slot_index(relative_weight, total_slots)
|
|
66
|
+
{
|
|
67
|
+
const raw_index = Math.floor(relative_weight * total_slots)
|
|
68
|
+
const clamped_index = Math.max(0, Math.min(total_slots - 1, raw_index))
|
|
69
|
+
return total_slots - 1 - clamped_index
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = { distribute_items_by_weight_range }
|
package/src/Allocation_Optimization/item_consumption_heuristic/exceptions/Empty_Slot_Exception.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { build_message_entry } = require('../../../messages/resolve_error_message_entry')
|
|
2
|
+
const { ALLOCATOR_MESSAGE } = require('../../../messages/Allocator_Message')
|
|
3
|
+
|
|
4
|
+
class Empty_Slot_Exception extends Error
|
|
5
|
+
{
|
|
6
|
+
/**
|
|
7
|
+
* @param {number} target_y
|
|
8
|
+
*/
|
|
9
|
+
constructor(target_y)
|
|
10
|
+
{
|
|
11
|
+
const message_key = ALLOCATOR_MESSAGE.EMPTY_SLOT
|
|
12
|
+
super(message_key)
|
|
13
|
+
this.message_entry = build_message_entry(message_key, [String(target_y)])
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = Empty_Slot_Exception
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const { build_message_entry } = require('../../../messages/resolve_error_message_entry')
|
|
2
|
+
const { ALLOCATOR_MESSAGE } = require('../../../messages/Allocator_Message')
|
|
3
|
+
|
|
4
|
+
class Item_Taller_Than_Limit_Exception extends Error
|
|
5
|
+
{
|
|
6
|
+
/**
|
|
7
|
+
* @param {number} height_limit
|
|
8
|
+
* @param {object} item
|
|
9
|
+
*/
|
|
10
|
+
constructor(height_limit, item)
|
|
11
|
+
{
|
|
12
|
+
const message_key = ALLOCATOR_MESSAGE.ITEM_TALLER_THAN_LIMIT
|
|
13
|
+
super(message_key)
|
|
14
|
+
this.message_entry = build_message_entry(
|
|
15
|
+
message_key,
|
|
16
|
+
[String(item.get_height()), String(height_limit)]
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = Item_Taller_Than_Limit_Exception
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { build_message_entry } = require('../../../messages/resolve_error_message_entry')
|
|
2
|
+
const { ALLOCATOR_MESSAGE } = require('../../../messages/Allocator_Message')
|
|
3
|
+
|
|
4
|
+
class No_Available_Items_Exception extends Error
|
|
5
|
+
{
|
|
6
|
+
constructor()
|
|
7
|
+
{
|
|
8
|
+
const message_key = ALLOCATOR_MESSAGE.NO_AVAILABLE_ITEMS
|
|
9
|
+
super(message_key)
|
|
10
|
+
this.message_entry = build_message_entry(message_key)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = No_Available_Items_Exception
|