Class: HeatingSystemCalculator::BaseElementFinder
- Inherits:
-
BaseItemFinder
- Object
- BaseItemFinder
- HeatingSystemCalculator::BaseElementFinder
- Defined in:
- app/services/heating_system_calculator/base_element_finder.rb
Overview
Service object: base element finder.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#coverage_percentage ⇒ Object
readonly
Returns the value of attribute coverage_percentage.
-
#elements ⇒ Object
readonly
Returns the value of attribute elements.
-
#error ⇒ Object
readonly
Returns the value of attribute error.
-
#target_area ⇒ Object
readonly
Returns the value of attribute target_area.
Instance Method Summary collapse
- #consolidate_elements(solution) ⇒ Object
- #find_best_solution(solutionset, targetarea, return_index_only = false) ⇒ Object
-
#initialize(options) ⇒ BaseElementFinder
constructor
A new instance of BaseElementFinder.
Methods inherited from BaseItemFinder
#get_number_of_poles_from_consolidated_elements, #get_total_from_solution
Constructor Details
#initialize(options) ⇒ BaseElementFinder
Returns a new instance of BaseElementFinder.
7 8 9 |
# File 'app/services/heating_system_calculator/base_element_finder.rb', line 7 def initialize() @element_set = [:element_set] end |
Instance Attribute Details
#coverage_percentage ⇒ Object (readonly)
Returns the value of attribute coverage_percentage.
5 6 7 |
# File 'app/services/heating_system_calculator/base_element_finder.rb', line 5 def coverage_percentage @coverage_percentage end |
#elements ⇒ Object (readonly)
Returns the value of attribute elements.
5 6 7 |
# File 'app/services/heating_system_calculator/base_element_finder.rb', line 5 def elements @elements end |
#error ⇒ Object (readonly)
Returns the value of attribute error.
5 6 7 |
# File 'app/services/heating_system_calculator/base_element_finder.rb', line 5 def error @error end |
#target_area ⇒ Object (readonly)
Returns the value of attribute target_area.
5 6 7 |
# File 'app/services/heating_system_calculator/base_element_finder.rb', line 5 def target_area @target_area end |
Instance Method Details
#consolidate_elements(solution) ⇒ Object
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'app/services/heating_system_calculator/base_element_finder.rb', line 11 def consolidate_elements(solution) # set up consolidated elements list elements = [] # loop over solution elements solution.each do |soln| # assume no duplicate products in the product set foundmatch = false # loop over our result set of unique elements elements.each do |elem| # test for duplicate product entries in the solution set next unless soln['sku'] == elem['sku'] # match found , increment quantity in our result set, set flag and break foundmatch = true elem['qty'] = elem['qty'] + (soln['qty'] || 1) break end next if foundmatch # no match found, so this is a unique entry in our result set elemnt = soln.merge({}) elemnt['qty'] ||= 1 elements << elemnt end elements end |
#find_best_solution(solutionset, targetarea, return_index_only = false) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'app/services/heating_system_calculator/base_element_finder.rb', line 38 def find_best_solution(solutionset, targetarea, return_index_only = false) # Priority: Prefer solutions that MEET OR EXCEED target over undersized ones # Among adequate solutions, prefer closest to target with lowest price threshold = 0.05 # Separate solutions into adequate (>= target) and undersized (< target) adequate_solutions = [] undersized_solutions = [] solutionset.each_with_index do |solution, i| area = get_total_from_solution(solution, 'area') if area >= targetarea adequate_solutions << [i, solution, area] else undersized_solutions << [i, solution, area] end end # Use adequate solutions if available, otherwise fall back to undersized candidates = adequate_solutions.any? ? adequate_solutions : undersized_solutions bestdiffarea = 99_999_999.0 bestprice = 99_999_999.0 bestsolnsetind = -1 best_length = 99_999 candidates.each do |i, solution, area| diffarea = (targetarea - area).abs price = get_total_from_solution(solution, 'price') # Select best solution: closest to target, then cheapest, then fewest pieces is_better = (diffarea < bestdiffarea && bestdiffarea > threshold * targetarea) || (diffarea < threshold * targetarea && price < bestprice) || (diffarea < threshold * targetarea && (price - bestprice).abs < threshold * bestprice && solution.length < best_length) next unless is_better bestsolnsetind = i bestdiffarea = diffarea bestprice = price best_length = solution.length end res = solutionset[bestsolnsetind] res = bestsolnsetind if return_index_only res end |