@@ -502,11 +502,9 @@ mod dynamic {
502502 /// Internal `WeightedRuin`/`WeightedRecreate` weight for weak members.
503503 const WEAK_BUNDLE_WEIGHT : usize = 1 ;
504504
505- /// Wraps every primary ruin in a `CompositeRuin` with a small-probability `extra_random_job`
506- /// companion to mimic today's "small chaos" baseline. `random_job` is its own primary, so we
507- /// skip the wrapper for it to avoid double-counting random destruction.
505+ /// Wraps every primary ruin in a `CompositeRuin` with a small-probability `extra`.
508506 fn wrap_with_extra ( ruin : Arc < dyn Ruin > , name : & str , extra : Arc < dyn Ruin > ) -> Arc < dyn Ruin > {
509- if name == "random_job" {
507+ if name == "random_job" || name == "random_route" {
510508 ruin
511509 } else {
512510 Arc :: new ( CompositeRuin :: new ( vec ! [ ( ruin, 1. ) , ( extra, 0.1 ) ] ) )
@@ -558,17 +556,14 @@ mod dynamic {
558556 as Arc < dyn Ruin >
559557 } ;
560558
559+ // random_job is omitted as a primary weak-tier as it seems not good to be used alone,
560+ // but it is still included as a small-probability companion in ruin bundles via `wrap_with_extra`.
561561 vec ! [
562562 (
563563 create_weighted( |limits| Arc :: new( NeighbourRemoval :: new( limits) ) ) ,
564564 "neighbour" . to_string( ) ,
565565 WEAK_ARM_PRIOR ,
566566 ) ,
567- (
568- create_weighted( |limits| Arc :: new( RandomJobRemoval :: new( limits) ) ) ,
569- "random_job" . to_string( ) ,
570- WEAK_ARM_PRIOR ,
571- ) ,
572567 (
573568 create_weighted( |limits| Arc :: new( RandomRouteRemoval :: new( limits) ) ) ,
574569 "random_route" . to_string( ) ,
@@ -577,10 +572,7 @@ mod dynamic {
577572 ]
578573 }
579574
580- fn get_strong_recreates (
581- problem : & Problem ,
582- random : Arc < dyn Random > ,
583- ) -> Vec < ( Arc < dyn Recreate > , String , Float ) > {
575+ fn get_strong_recreates ( problem : & Problem , random : Arc < dyn Random > ) -> Vec < ( Arc < dyn Recreate > , String , Float ) > {
584576 let blinks: Arc < dyn Recreate > = Arc :: new ( RecreateWithBlinks :: new_with_defaults ( random. clone ( ) ) ) ;
585577 let cheapest: Arc < dyn Recreate > = Arc :: new ( RecreateWithCheapest :: new ( random. clone ( ) ) ) ;
586578 let regret: Arc < dyn Recreate > = Arc :: new ( RecreateWithRegret :: new ( 1 , 3 , random. clone ( ) ) ) ;
@@ -643,13 +635,9 @@ mod dynamic {
643635 ) -> Arc < dyn Ruin > {
644636 let mut bundle: Vec < ( Arc < dyn Ruin > , usize ) > = Vec :: with_capacity ( strong. len ( ) + weak. len ( ) ) ;
645637 bundle. extend (
646- strong
647- . iter ( )
648- . map ( |( r, n, _) | ( wrap_with_extra ( r. clone ( ) , n, extra. clone ( ) ) , STRONG_BUNDLE_WEIGHT ) ) ,
649- ) ;
650- bundle. extend (
651- weak. iter ( ) . map ( |( r, n, _) | ( wrap_with_extra ( r. clone ( ) , n, extra. clone ( ) ) , WEAK_BUNDLE_WEIGHT ) ) ,
638+ strong. iter ( ) . map ( |( r, n, _) | ( wrap_with_extra ( r. clone ( ) , n, extra. clone ( ) ) , STRONG_BUNDLE_WEIGHT ) ) ,
652639 ) ;
640+ bundle. extend ( weak. iter ( ) . map ( |( r, n, _) | ( wrap_with_extra ( r. clone ( ) , n, extra. clone ( ) ) , WEAK_BUNDLE_WEIGHT ) ) ) ;
653641 Arc :: new ( WeightedRuin :: new ( bundle) )
654642 }
655643
@@ -707,7 +695,13 @@ mod dynamic {
707695 let strong_recreates = get_strong_recreates ( problem. as_ref ( ) , random. clone ( ) ) ;
708696 let weak_recreates = get_weak_recreates ( random. clone ( ) ) ;
709697
710- let extra_random_job: Arc < dyn Ruin > = Arc :: new ( RandomJobRemoval :: new ( small_limits) ) ;
698+ // 3:1 weighted mix of random_job and random_route — applied at 0.1 probability to every
699+ // primary ruin via wrap_with_extra. Random_route occasionally forces job redistribution
700+ // across routes, which scattered random_job removal can't trigger.
701+ let extra_random_job: Arc < dyn Ruin > = Arc :: new ( WeightedRuin :: new ( vec ! [
702+ ( Arc :: new( RandomJobRemoval :: new( small_limits. clone( ) ) ) as Arc <dyn Ruin >, 3 ) ,
703+ ( Arc :: new( RandomRouteRemoval :: new( small_limits) ) as Arc <dyn Ruin >, 1 ) ,
704+ ] ) ) ;
711705
712706 // Strong cartesian: every strong ruin × every strong recreate. Ruins are wrapped with the
713707 // small `extra_random_job` companion (today's "small chaos" baseline).
@@ -739,17 +733,12 @@ mod dynamic {
739733 . iter ( )
740734 . map :: < ( TargetSearchOperator , String , Float ) , _ > ( |( ruin, name, weight) | {
741735 let primary = wrap_with_extra ( ruin. clone ( ) , name, extra_random_job. clone ( ) ) ;
742- (
743- Arc :: new ( RuinAndRecreate :: new ( primary, weak_ruin_recreate_bundle. clone ( ) ) ) ,
744- name. clone ( ) ,
745- * weight,
746- )
736+ ( Arc :: new ( RuinAndRecreate :: new ( primary, weak_ruin_recreate_bundle. clone ( ) ) ) , name. clone ( ) , * weight)
747737 } )
748738 . collect :: < Vec < _ > > ( ) ;
749739
750740 // Weak recreate arms: each weak recreate paired with a strong-heavy WeightedRuin bundle.
751- let weak_recreate_ruin_bundle =
752- build_weak_ruin_bundle ( & strong_ruins, & weak_ruins, extra_random_job) ;
741+ let weak_recreate_ruin_bundle = build_weak_ruin_bundle ( & strong_ruins, & weak_ruins, extra_random_job) ;
753742 let weak_recreate_ops = weak_recreates
754743 . iter ( )
755744 . map :: < ( TargetSearchOperator , String , Float ) , _ > ( |( recreate, name, weight) | {
@@ -782,8 +771,6 @@ mod dynamic {
782771 }
783772
784773 /// Creates a default ruin-and-recreate operator for internal use (e.g., decompose search, infeasible search).
785- /// Uses the same tier philosophy as the main bandit: strong members dominate (2:1 over weak)
786- /// inside both the ruin and recreate bundles, with the SISR pair (asr, blinks) further boosted.
787774 pub fn create_default_inner_ruin_recreate (
788775 problem : Arc < Problem > ,
789776 environment : Arc < Environment > ,
@@ -792,36 +779,32 @@ mod dynamic {
792779 let random = environment. random . clone ( ) ;
793780
794781 let strong_ruins = get_strong_ruins ( problem. clone ( ) , & normal_limits, & small_limits) ;
795- let weak_ruins = get_weak_ruins ( & normal_limits, & small_limits) ;
796- let strong_recreates = get_strong_recreates ( problem. as_ref ( ) , random. clone ( ) ) ;
797- let weak_recreates = get_weak_recreates ( random) ;
782+ let strong_recreates = get_strong_recreates ( problem. as_ref ( ) , random) ;
798783
799- let extra_random_job: Arc < dyn Ruin > = Arc :: new ( RandomJobRemoval :: new ( small_limits) ) ;
784+ // 3:1 mix of random_job and random_route as the small-chaos companion (matches outer pool).
785+ let extra_random: Arc < dyn Ruin > = Arc :: new ( WeightedRuin :: new ( vec ! [
786+ ( Arc :: new( RandomJobRemoval :: new( small_limits. clone( ) ) ) as Arc <dyn Ruin >, 3 ) ,
787+ ( Arc :: new( RandomRouteRemoval :: new( small_limits) ) as Arc <dyn Ruin >, 1 ) ,
788+ ] ) ) ;
800789
801- // Map bandit-prior weights to integer bundle weights, preserving the SISR boost
802- // (asr=3, blinks=3) and the strong/weak split. Weak members at half-weight after rounding,
803- // so we use an explicit table instead of casting Float→usize.
790+ // Map bandit-prior weights to integer bundle weights, preserving the SISR boost (asr=3, blinks=3).
804791 let to_bundle_weight = |float_weight : Float | -> usize {
805792 if float_weight >= SISR_BOOST_WEIGHT {
806793 SISR_BOOST_WEIGHT as usize * STRONG_BUNDLE_WEIGHT
807- } else if float_weight >= STRONG_WEIGHT {
808- STRONG_BUNDLE_WEIGHT
809794 } else {
810- WEAK_BUNDLE_WEIGHT
795+ STRONG_BUNDLE_WEIGHT
811796 }
812797 } ;
813798
814799 let weighted_ruins: Vec < ( Arc < dyn Ruin > , usize ) > = strong_ruins
815800 . iter ( )
816- . chain ( weak_ruins. iter ( ) )
817801 . map ( |( ruin, name, weight) | {
818- ( wrap_with_extra ( ruin. clone ( ) , name, extra_random_job . clone ( ) ) , to_bundle_weight ( * weight) )
802+ ( wrap_with_extra ( ruin. clone ( ) , name, extra_random . clone ( ) ) , to_bundle_weight ( * weight) )
819803 } )
820804 . collect ( ) ;
821805
822806 let weighted_recreates: Vec < ( Arc < dyn Recreate > , usize ) > = strong_recreates
823807 . iter ( )
824- . chain ( weak_recreates. iter ( ) )
825808 . map ( |( recreate, _, weight) | ( recreate. clone ( ) , to_bundle_weight ( * weight) ) )
826809 . collect ( ) ;
827810
0 commit comments