Class: CrossEntropy::AbstractProblem

Inherits:
Object
  • Object
show all
Defined in:
lib/cross_entropy/abstract_problem.rb

Overview

Base class for specific problem types.

Direct Known Subclasses

BetaProblem, ContinuousProblem, MatrixProblem

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params) {|_self| ... } ⇒ AbstractProblem

Returns a new instance of AbstractProblem.

Parameters:

  • params (Array)

Yields:

  • (_self)

Yield Parameters:



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/cross_entropy/abstract_problem.rb', line 11

def initialize(params)
  @params = params

  @max_iters = nil
  @track_overall_min = false
  @overall_min_score = 1.0 / 0.0
  @overall_min_score_sample = nil

  @generate_samples = proc { raise 'no generating function provided' }
  @score_sample     = proc { |_sample| raise 'no score block provided' }
  @estimate         = proc { |_elite| raise 'no estimate block provided' }
  @update           = proc { |estimated_params| estimated_params }
  @stop_decision    = proc do
    raise 'no max_iters provided' unless max_iters
    num_iters >= max_iters
  end

  yield(self) if block_given?
end

Instance Attribute Details

#elite_scoreObject (readonly)

Returns the value of attribute elite_score.



59
60
61
# File 'lib/cross_entropy/abstract_problem.rb', line 59

def elite_score
  @elite_score
end

#max_itersObject

Returns the value of attribute max_iters.



35
36
37
# File 'lib/cross_entropy/abstract_problem.rb', line 35

def max_iters
  @max_iters
end

#min_scoreObject (readonly)

Returns the value of attribute min_score.



58
59
60
# File 'lib/cross_entropy/abstract_problem.rb', line 58

def min_score
  @min_score
end

#num_eliteObject

Returns the value of attribute num_elite.



34
35
36
# File 'lib/cross_entropy/abstract_problem.rb', line 34

def num_elite
  @num_elite
end

#num_itersObject (readonly)

Returns the value of attribute num_iters.



57
58
59
# File 'lib/cross_entropy/abstract_problem.rb', line 57

def num_iters
  @num_iters
end

#num_samplesObject

Returns the value of attribute num_samples.



33
34
35
# File 'lib/cross_entropy/abstract_problem.rb', line 33

def num_samples
  @num_samples
end

#overall_min_scoreObject (readonly)

Keep track of the best sample we’ve ever seen; if the scoring function is deterministic, then this is a quantity of major interest.



63
64
65
# File 'lib/cross_entropy/abstract_problem.rb', line 63

def overall_min_score
  @overall_min_score
end

#overall_min_score_sampleObject (readonly)

Returns the value of attribute overall_min_score_sample.



64
65
66
# File 'lib/cross_entropy/abstract_problem.rb', line 64

def overall_min_score_sample
  @overall_min_score_sample
end

#paramsObject

Returns the value of attribute params.



31
32
33
# File 'lib/cross_entropy/abstract_problem.rb', line 31

def params
  @params
end

#track_overall_minObject

Returns the value of attribute track_overall_min.



65
66
67
# File 'lib/cross_entropy/abstract_problem.rb', line 65

def track_overall_min
  @track_overall_min
end

Instance Method Details

#for_stop_decision(&block) ⇒ Object



53
54
55
# File 'lib/cross_entropy/abstract_problem.rb', line 53

def for_stop_decision(&block)
  @stop_decision = block
end

#solveObject

Generic cross entropy routine.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/cross_entropy/abstract_problem.rb', line 70

def solve
  @num_iters = 0

  loop do
    @min_score   = nil
    @elite_score = nil

    samples = @generate_samples.call

    # Score each sample.
    scores = NArray.float(num_samples)
    (0...num_samples).each do |i|
      sample_i = samples[i, true]
      score_i  = @score_sample.call(sample_i)

      # Keep track of best ever if requested.
      if track_overall_min && score_i < overall_min_score
        @overall_min_score        = score_i
        @overall_min_score_sample = sample_i
      end

      scores[i] = score_i
    end

    # Find elite quantile (gamma).
    scores_sorted = scores.sort
    @min_score   = scores_sorted[0]
    @elite_score = scores_sorted[num_elite - 1]

    # Take all samples with scores below (or equal to) gamma; note that
    # there may be more than num_elite, due to ties.
    elite = samples[(scores <= elite_score).where, true]

    # Compute new parameter estimates.
    estimated_params = @estimate.call(elite)

    # Update main parameter estimates.
    self.params = @update.call(estimated_params)

    @num_iters += 1
    break if @stop_decision.call
  end
end

#to_estimate(&block) ⇒ Object



45
46
47
# File 'lib/cross_entropy/abstract_problem.rb', line 45

def to_estimate(&block)
  @estimate = block
end

#to_generate_samples(&block) ⇒ Object



37
38
39
# File 'lib/cross_entropy/abstract_problem.rb', line 37

def to_generate_samples(&block)
  @generate_samples = block
end

#to_score_sample(&block) ⇒ Object



41
42
43
# File 'lib/cross_entropy/abstract_problem.rb', line 41

def to_score_sample(&block)
  @score_sample = block
end

#to_update(&block) ⇒ Object



49
50
51
# File 'lib/cross_entropy/abstract_problem.rb', line 49

def to_update(&block)
  @update = block
end