Class: Roby::Schedulers::Global::SchedulingGroup

Inherits:
Struct
  • Object
show all
Defined in:
lib/roby/schedulers/global.rb

Overview

Representation of a group of tasks that should be scheduled together or not at all

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#can_scheduleObject

Returns the value of attribute can_schedule

Returns:

  • (Object)

    the current value of can_schedule



743
744
745
# File 'lib/roby/schedulers/global.rb', line 743

def can_schedule
  @can_schedule
end

#external_temporal_constraintsObject

Returns the value of attribute external_temporal_constraints

Returns:

  • (Object)

    the current value of external_temporal_constraints



743
744
745
# File 'lib/roby/schedulers/global.rb', line 743

def external_temporal_constraints
  @external_temporal_constraints
end

#held_by_temporalObject

Returns the value of attribute held_by_temporal

Returns:

  • (Object)

    the current value of held_by_temporal



743
744
745
# File 'lib/roby/schedulers/global.rb', line 743

def held_by_temporal
  @held_by_temporal
end

#held_non_executableObject

Returns the value of attribute held_non_executable

Returns:

  • (Object)

    the current value of held_non_executable



743
744
745
# File 'lib/roby/schedulers/global.rb', line 743

def held_non_executable
  @held_non_executable
end

#held_non_schedulableObject

Returns the value of attribute held_non_schedulable

Returns:

  • (Object)

    the current value of held_non_schedulable



743
744
745
# File 'lib/roby/schedulers/global.rb', line 743

def held_non_schedulable
  @held_non_schedulable
end

#idObject

Returns the value of attribute id

Returns:

  • (Object)

    the current value of id



743
744
745
# File 'lib/roby/schedulers/global.rb', line 743

def id
  @id
end

#non_executable_tasksObject

Returns the value of attribute non_executable_tasks

Returns:

  • (Object)

    the current value of non_executable_tasks



743
744
745
# File 'lib/roby/schedulers/global.rb', line 743

def non_executable_tasks
  @non_executable_tasks
end

#stateObject

Returns the value of attribute state

Returns:

  • (Object)

    the current value of state



743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
# File 'lib/roby/schedulers/global.rb', line 743

SchedulingGroup = Struct.new(
    :tasks, :temporal_constraints, :external_temporal_constraints,
    :can_schedule, :non_executable_tasks,
    :held_by_temporal, :held_non_schedulable, :held_non_executable,
    :state, :id, keyword_init: true
) do
    def self.for_tasks(tasks:, id:)
        SchedulingGroup.new(
            tasks: tasks, id: id,
            held_by_temporal: Set.new,
            held_non_schedulable: Set.new,
            held_non_executable: Set.new,
            non_executable_tasks: Set.new
        )
    end

    def each(&block)
        tasks.each(&block)
    end

    def scheduling_constraint_state(logger: nil)
        if !held_non_schedulable.empty?
            logger&.debug "#{id} is held by non-schedulable groups"
            STATE_NON_SCHEDULABLE
        elsif !held_non_executable.empty?
            logger&.debug "#{id} is held by non-executable groups"
            STATE_PENDING_CONSTRAINTS
        elsif !held_by_temporal.empty?
            logger&.debug "#{id} is held by temporal constraints within " \
                  "the scheduling groups"
            STATE_PENDING_CONSTRAINTS
        end
    end

    def resolve_state(logger: nil)
        state = nil

        debug_output_resolve_state(logger) if logger

        unless non_executable_tasks.empty?
            held_non_executable << self
            state = STATE_PENDING_CONSTRAINTS
        end

        if !can_schedule
            held_non_schedulable << self
            state = STATE_NON_SCHEDULABLE
        elsif external_temporal_constraints
            held_non_schedulable << self
            state = STATE_NON_SCHEDULABLE
        else
            state = scheduling_constraint_state(logger: logger) || state
        end

        state || STATE_SCHEDULABLE
    end

    def debug_output_resolve_state(logger)
        return unless Roby.log_level_enabled?(logger, :debug)

        unless non_executable_tasks.empty?
            logger.debug "#{id} has non-executable tasks"
        end
        logger.debug "#{id} has !can_schedule" unless can_schedule
        if external_temporal_constraints
            logger.debug "#{id} has external temporal constraints"
        end

        nil
    end

    def hash
        object_id
    end

    def ==(other)
        equal?(other)
    end

    def eql?(other)
        equal?(other)
    end

    # Assuming this group can be scheduled, return the tasks that should
    # be scheduled for it
    def resolve_tasks_to_schedule(set, time)
        if held_by_temporal.empty?
            set.merge(tasks)
        else
            held_by_temporal.each do |group|
                related_tasks = group.temporal_constraints.related_tasks
                related_schedulable =
                    find_all_schedulable(related_tasks, time)
                set.merge(related_schedulable)
            end
        end
    end

    def find_all_schedulable(tasks, time)
        tasks = tasks.find_all(&:executable?)
        tasks.find_all do |t|
            start = t.start_event
            has_failed_temporal =
                start.each_failed_temporal_constraint(time).any?
            has_failed_occurence =
                start.each_failed_occurence_constraint(use_last_event: true)
                     .any?
            !has_failed_occurence && !has_failed_temporal
        end
    end

    # Tests whether this group is in a state that is compatible with
    # state relaxation
    #
    # @see {Global#relax_group_scheduling_constraints}
    def state_compatible_with_relaxation?
        STATES_COMPATIBLE_WITH_RELAXATION.include?(state)
    end
end

#tasksObject

Returns the value of attribute tasks

Returns:

  • (Object)

    the current value of tasks



743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
# File 'lib/roby/schedulers/global.rb', line 743

SchedulingGroup = Struct.new(
    :tasks, :temporal_constraints, :external_temporal_constraints,
    :can_schedule, :non_executable_tasks,
    :held_by_temporal, :held_non_schedulable, :held_non_executable,
    :state, :id, keyword_init: true
) do
    def self.for_tasks(tasks:, id:)
        SchedulingGroup.new(
            tasks: tasks, id: id,
            held_by_temporal: Set.new,
            held_non_schedulable: Set.new,
            held_non_executable: Set.new,
            non_executable_tasks: Set.new
        )
    end

    def each(&block)
        tasks.each(&block)
    end

    def scheduling_constraint_state(logger: nil)
        if !held_non_schedulable.empty?
            logger&.debug "#{id} is held by non-schedulable groups"
            STATE_NON_SCHEDULABLE
        elsif !held_non_executable.empty?
            logger&.debug "#{id} is held by non-executable groups"
            STATE_PENDING_CONSTRAINTS
        elsif !held_by_temporal.empty?
            logger&.debug "#{id} is held by temporal constraints within " \
                  "the scheduling groups"
            STATE_PENDING_CONSTRAINTS
        end
    end

    def resolve_state(logger: nil)
        state = nil

        debug_output_resolve_state(logger) if logger

        unless non_executable_tasks.empty?
            held_non_executable << self
            state = STATE_PENDING_CONSTRAINTS
        end

        if !can_schedule
            held_non_schedulable << self
            state = STATE_NON_SCHEDULABLE
        elsif external_temporal_constraints
            held_non_schedulable << self
            state = STATE_NON_SCHEDULABLE
        else
            state = scheduling_constraint_state(logger: logger) || state
        end

        state || STATE_SCHEDULABLE
    end

    def debug_output_resolve_state(logger)
        return unless Roby.log_level_enabled?(logger, :debug)

        unless non_executable_tasks.empty?
            logger.debug "#{id} has non-executable tasks"
        end
        logger.debug "#{id} has !can_schedule" unless can_schedule
        if external_temporal_constraints
            logger.debug "#{id} has external temporal constraints"
        end

        nil
    end

    def hash
        object_id
    end

    def ==(other)
        equal?(other)
    end

    def eql?(other)
        equal?(other)
    end

    # Assuming this group can be scheduled, return the tasks that should
    # be scheduled for it
    def resolve_tasks_to_schedule(set, time)
        if held_by_temporal.empty?
            set.merge(tasks)
        else
            held_by_temporal.each do |group|
                related_tasks = group.temporal_constraints.related_tasks
                related_schedulable =
                    find_all_schedulable(related_tasks, time)
                set.merge(related_schedulable)
            end
        end
    end

    def find_all_schedulable(tasks, time)
        tasks = tasks.find_all(&:executable?)
        tasks.find_all do |t|
            start = t.start_event
            has_failed_temporal =
                start.each_failed_temporal_constraint(time).any?
            has_failed_occurence =
                start.each_failed_occurence_constraint(use_last_event: true)
                     .any?
            !has_failed_occurence && !has_failed_temporal
        end
    end

    # Tests whether this group is in a state that is compatible with
    # state relaxation
    #
    # @see {Global#relax_group_scheduling_constraints}
    def state_compatible_with_relaxation?
        STATES_COMPATIBLE_WITH_RELAXATION.include?(state)
    end
end

#temporal_constraintsObject

Returns the value of attribute temporal_constraints

Returns:

  • (Object)

    the current value of temporal_constraints



743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
# File 'lib/roby/schedulers/global.rb', line 743

SchedulingGroup = Struct.new(
    :tasks, :temporal_constraints, :external_temporal_constraints,
    :can_schedule, :non_executable_tasks,
    :held_by_temporal, :held_non_schedulable, :held_non_executable,
    :state, :id, keyword_init: true
) do
    def self.for_tasks(tasks:, id:)
        SchedulingGroup.new(
            tasks: tasks, id: id,
            held_by_temporal: Set.new,
            held_non_schedulable: Set.new,
            held_non_executable: Set.new,
            non_executable_tasks: Set.new
        )
    end

    def each(&block)
        tasks.each(&block)
    end

    def scheduling_constraint_state(logger: nil)
        if !held_non_schedulable.empty?
            logger&.debug "#{id} is held by non-schedulable groups"
            STATE_NON_SCHEDULABLE
        elsif !held_non_executable.empty?
            logger&.debug "#{id} is held by non-executable groups"
            STATE_PENDING_CONSTRAINTS
        elsif !held_by_temporal.empty?
            logger&.debug "#{id} is held by temporal constraints within " \
                  "the scheduling groups"
            STATE_PENDING_CONSTRAINTS
        end
    end

    def resolve_state(logger: nil)
        state = nil

        debug_output_resolve_state(logger) if logger

        unless non_executable_tasks.empty?
            held_non_executable << self
            state = STATE_PENDING_CONSTRAINTS
        end

        if !can_schedule
            held_non_schedulable << self
            state = STATE_NON_SCHEDULABLE
        elsif external_temporal_constraints
            held_non_schedulable << self
            state = STATE_NON_SCHEDULABLE
        else
            state = scheduling_constraint_state(logger: logger) || state
        end

        state || STATE_SCHEDULABLE
    end

    def debug_output_resolve_state(logger)
        return unless Roby.log_level_enabled?(logger, :debug)

        unless non_executable_tasks.empty?
            logger.debug "#{id} has non-executable tasks"
        end
        logger.debug "#{id} has !can_schedule" unless can_schedule
        if external_temporal_constraints
            logger.debug "#{id} has external temporal constraints"
        end

        nil
    end

    def hash
        object_id
    end

    def ==(other)
        equal?(other)
    end

    def eql?(other)
        equal?(other)
    end

    # Assuming this group can be scheduled, return the tasks that should
    # be scheduled for it
    def resolve_tasks_to_schedule(set, time)
        if held_by_temporal.empty?
            set.merge(tasks)
        else
            held_by_temporal.each do |group|
                related_tasks = group.temporal_constraints.related_tasks
                related_schedulable =
                    find_all_schedulable(related_tasks, time)
                set.merge(related_schedulable)
            end
        end
    end

    def find_all_schedulable(tasks, time)
        tasks = tasks.find_all(&:executable?)
        tasks.find_all do |t|
            start = t.start_event
            has_failed_temporal =
                start.each_failed_temporal_constraint(time).any?
            has_failed_occurence =
                start.each_failed_occurence_constraint(use_last_event: true)
                     .any?
            !has_failed_occurence && !has_failed_temporal
        end
    end

    # Tests whether this group is in a state that is compatible with
    # state relaxation
    #
    # @see {Global#relax_group_scheduling_constraints}
    def state_compatible_with_relaxation?
        STATES_COMPATIBLE_WITH_RELAXATION.include?(state)
    end
end

Class Method Details

.for_tasks(tasks:, id:) ⇒ Object



749
750
751
752
753
754
755
756
757
# File 'lib/roby/schedulers/global.rb', line 749

def self.for_tasks(tasks:, id:)
    SchedulingGroup.new(
        tasks: tasks, id: id,
        held_by_temporal: Set.new,
        held_non_schedulable: Set.new,
        held_non_executable: Set.new,
        non_executable_tasks: Set.new
    )
end

Instance Method Details

#==(other) ⇒ Object



818
819
820
# File 'lib/roby/schedulers/global.rb', line 818

def ==(other)
    equal?(other)
end

#debug_output_resolve_state(logger) ⇒ Object



800
801
802
803
804
805
806
807
808
809
810
811
812
# File 'lib/roby/schedulers/global.rb', line 800

def debug_output_resolve_state(logger)
    return unless Roby.log_level_enabled?(logger, :debug)

    unless non_executable_tasks.empty?
        logger.debug "#{id} has non-executable tasks"
    end
    logger.debug "#{id} has !can_schedule" unless can_schedule
    if external_temporal_constraints
        logger.debug "#{id} has external temporal constraints"
    end

    nil
end

#each(&block) ⇒ Object



759
760
761
# File 'lib/roby/schedulers/global.rb', line 759

def each(&block)
    tasks.each(&block)
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


822
823
824
# File 'lib/roby/schedulers/global.rb', line 822

def eql?(other)
    equal?(other)
end

#find_all_schedulable(tasks, time) ⇒ Object



841
842
843
844
845
846
847
848
849
850
851
852
# File 'lib/roby/schedulers/global.rb', line 841

def find_all_schedulable(tasks, time)
    tasks = tasks.find_all(&:executable?)
    tasks.find_all do |t|
        start = t.start_event
        has_failed_temporal =
            start.each_failed_temporal_constraint(time).any?
        has_failed_occurence =
            start.each_failed_occurence_constraint(use_last_event: true)
                 .any?
        !has_failed_occurence && !has_failed_temporal
    end
end

#hashObject



814
815
816
# File 'lib/roby/schedulers/global.rb', line 814

def hash
    object_id
end

#resolve_state(logger: nil) ⇒ Object



777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
# File 'lib/roby/schedulers/global.rb', line 777

def resolve_state(logger: nil)
    state = nil

    debug_output_resolve_state(logger) if logger

    unless non_executable_tasks.empty?
        held_non_executable << self
        state = STATE_PENDING_CONSTRAINTS
    end

    if !can_schedule
        held_non_schedulable << self
        state = STATE_NON_SCHEDULABLE
    elsif external_temporal_constraints
        held_non_schedulable << self
        state = STATE_NON_SCHEDULABLE
    else
        state = scheduling_constraint_state(logger: logger) || state
    end

    state || STATE_SCHEDULABLE
end

#resolve_tasks_to_schedule(set, time) ⇒ Object

Assuming this group can be scheduled, return the tasks that should be scheduled for it



828
829
830
831
832
833
834
835
836
837
838
839
# File 'lib/roby/schedulers/global.rb', line 828

def resolve_tasks_to_schedule(set, time)
    if held_by_temporal.empty?
        set.merge(tasks)
    else
        held_by_temporal.each do |group|
            related_tasks = group.temporal_constraints.related_tasks
            related_schedulable =
                find_all_schedulable(related_tasks, time)
            set.merge(related_schedulable)
        end
    end
end

#scheduling_constraint_state(logger: nil) ⇒ Object



763
764
765
766
767
768
769
770
771
772
773
774
775
# File 'lib/roby/schedulers/global.rb', line 763

def scheduling_constraint_state(logger: nil)
    if !held_non_schedulable.empty?
        logger&.debug "#{id} is held by non-schedulable groups"
        STATE_NON_SCHEDULABLE
    elsif !held_non_executable.empty?
        logger&.debug "#{id} is held by non-executable groups"
        STATE_PENDING_CONSTRAINTS
    elsif !held_by_temporal.empty?
        logger&.debug "#{id} is held by temporal constraints within " \
              "the scheduling groups"
        STATE_PENDING_CONSTRAINTS
    end
end

#state_compatible_with_relaxation?Boolean

Tests whether this group is in a state that is compatible with state relaxation

Returns:

  • (Boolean)

See Also:

  • Roby::Schedulers::Global::SchedulingGroup.{Global{Global#relax_group_scheduling_constraints}


858
859
860
# File 'lib/roby/schedulers/global.rb', line 858

def state_compatible_with_relaxation?
    STATES_COMPATIBLE_WITH_RELAXATION.include?(state)
end