Class: SuperInstance::Equipment::ConsensusEngine::WeightCalculator

Inherits:
Object
  • Object
show all
Defined in:
lib/equipment/consensus_engine/weight_calculator.rb

Overview

WeightCalculator - Domain-specific weight calculation for perspectives

Calculates appropriate weights for Pathos, Logos, and Ethos perspectives based on the domain of the deliberation.

Examples:

calculator = SuperInstance::Equipment::ConsensusEngine::WeightCalculator.new

# Get weights for a factual domain
factual_profile = calculator.get_profile(:factual)
puts factual_profile[:logos_weight]  # 0.60

# Calculate adjusted weights based on content
adjusted = calculator.calculate_adjusted_weights(
  :sensitive,
  'This decision affects vulnerable populations...'
)

Constant Summary collapse

DOMAIN_CHARACTERISTICS =

Domain characteristics for analysis

{
  factual: {
    emotional_importance: 0.2,
    logical_importance: 0.8,
    ethical_importance: 0.4,
    uncertainty_level: 0.3,
    stakeholder_complexity: 0.3
  },
  emotional: {
    emotional_importance: 0.8,
    logical_importance: 0.3,
    ethical_importance: 0.5,
    uncertainty_level: 0.5,
    stakeholder_complexity: 0.7
  },
  sensitive: {
    emotional_importance: 0.6,
    logical_importance: 0.4,
    ethical_importance: 0.9,
    uncertainty_level: 0.4,
    stakeholder_complexity: 0.8
  },
  creative: {
    emotional_importance: 0.7,
    logical_importance: 0.5,
    ethical_importance: 0.4,
    uncertainty_level: 0.6,
    stakeholder_complexity: 0.4
  },
  balanced: {
    emotional_importance: 0.5,
    logical_importance: 0.5,
    ethical_importance: 0.5,
    uncertainty_level: 0.5,
    stakeholder_complexity: 0.5
  },
  technical: {
    emotional_importance: 0.1,
    logical_importance: 0.9,
    ethical_importance: 0.3,
    uncertainty_level: 0.2,
    stakeholder_complexity: 0.2
  },
  social: {
    emotional_importance: 0.7,
    logical_importance: 0.4,
    ethical_importance: 0.6,
    uncertainty_level: 0.5,
    stakeholder_complexity: 0.9
  },
  business: {
    emotional_importance: 0.4,
    logical_importance: 0.7,
    ethical_importance: 0.5,
    uncertainty_level: 0.4,
    stakeholder_complexity: 0.6
  },
  maritime: {
    emotional_importance: 0.3,
    logical_importance: 0.8,
    ethical_importance: 0.6,
    uncertainty_level: 0.5,
    stakeholder_complexity: 0.4
  },
  personal: {
    emotional_importance: 0.8,
    logical_importance: 0.4,
    ethical_importance: 0.4,
    uncertainty_level: 0.6,
    stakeholder_complexity: 0.3
  }
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(custom_weights = {}) ⇒ WeightCalculator

Creates a new WeightCalculator instance

Parameters:

  • custom_weights (Hash) (defaults to: {})

    Optional custom weight overrides to apply to all profiles



102
103
104
105
# File 'lib/equipment/consensus_engine/weight_calculator.rb', line 102

def initialize(custom_weights = {})
  @profiles = build_default_profiles
  @custom_overrides = custom_weights
end

Instance Method Details

#blend_domains(domains) ⇒ Hash

Creates a custom weight profile by blending multiple domains

Parameters:

  • domains (Array<Hash>)

    Domains to blend with weights [{ domain: :factual, weight: 0.5 }]

Returns:

  • (Hash)

    Blended weight profile



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/equipment/consensus_engine/weight_calculator.rb', line 227

def blend_domains(domains)
  if domains.empty?
    return get_profile(:balanced)
  end

  # Normalize input weights
  total_input_weight = domains.sum { |d| d[:weight] }
  normalized_domains = domains.map do |d|
    { domain: d[:domain], weight: d[:weight] / total_input_weight }
  end

  # Blend the weights
  pathos_weight = 0.0
  logos_weight = 0.0
  ethos_weight = 0.0
  all_rules = []

  normalized_domains.each do |item|
    profile = get_profile(item[:domain])
    pathos_weight += profile[:pathos_weight] * item[:weight]
    logos_weight += profile[:logos_weight] * item[:weight]
    ethos_weight += profile[:ethos_weight] * item[:weight]
    all_rules.concat(profile[:adjustment_rules] || [])
  end

  # Normalize to sum to 1
  total = pathos_weight + logos_weight + ethos_weight

  {
    pathos_weight: pathos_weight / total,
    logos_weight: logos_weight / total,
    ethos_weight: ethos_weight / total,
    domain: :balanced,
    description: "Blended profile from: #{domains.map { |d| d[:domain] }.join(', ')}",
    adjustment_rules: all_rules
  }
end

#calculate_adjusted_weights(domain, content, base_weights = nil) ⇒ Hash

Calculates adjusted weights based on content analysis

Parameters:

  • domain (Symbol)

    The base domain

  • content (String)

    The content to analyze

  • base_weights (Hash, nil) (defaults to: nil)

    Optional base weights to start from

Returns:

  • (Hash)

    Adjusted weight profile



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/equipment/consensus_engine/weight_calculator.rb', line 146

def calculate_adjusted_weights(domain, content, base_weights = nil)
  base_profile = base_weights || get_profile(domain)
  rules = base_profile[:adjustment_rules] || []

  # Sort rules by priority
  sorted_rules = rules.sort_by { |r| -r[:priority] }

  pathos_weight = base_profile[:pathos_weight]
  logos_weight = base_profile[:logos_weight]
  ethos_weight = base_profile[:ethos_weight]

  # Apply matching rules
  sorted_rules.each do |rule|
    if matches_condition(content, rule[:condition])
      case rule[:perspective]
      when :pathos
        pathos_weight += rule[:adjustment]
      when :logos
        logos_weight += rule[:adjustment]
      when :ethos
        ethos_weight += rule[:adjustment]
      end
    end
  end

  # Normalize to sum to 1
  total = pathos_weight + logos_weight + ethos_weight

  {
    pathos_weight: pathos_weight / total,
    logos_weight: logos_weight / total,
    ethos_weight: ethos_weight / total,
    domain: domain,
    description: "Adjusted profile for #{domain} domain based on content analysis",
    adjustment_rules: rules
  }
end

#detect_domain(content) ⇒ Symbol

Detects the most appropriate domain from content

Parameters:

  • content (String)

    The content to analyze

Returns:

  • (Symbol)

    The detected domain



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/equipment/consensus_engine/weight_calculator.rb', line 187

def detect_domain(content)
  lower_content = content.downcase
  scores = []

  # Check for each domain type
  scores << { domain: :factual, score: score_domain(lower_content, DomainKeywords::FACTUAL) }
  scores << { domain: :emotional, score: score_domain(lower_content, DomainKeywords::EMOTIONAL) }
  scores << { domain: :sensitive, score: score_domain(lower_content, DomainKeywords::SENSITIVE) }
  scores << { domain: :creative, score: score_domain(lower_content, DomainKeywords::CREATIVE) }
  scores << { domain: :technical, score: score_domain(lower_content, DomainKeywords::TECHNICAL) }
  scores << { domain: :social, score: score_domain(lower_content, DomainKeywords::SOCIAL) }
  scores << { domain: :business, score: score_domain(lower_content, DomainKeywords::BUSINESS) }
  scores << { domain: :personal, score: score_domain(lower_content, DomainKeywords::PERSONAL) }
  scores << { domain: :maritime, score: score_domain(lower_content, DomainKeywords::MARITIME) }

  # Find highest score
  scores.sort! { |a, b| b[:score] <=> a[:score] }

  # If no strong signal, return balanced
  return :balanced if scores[0][:score] < 3

  scores[0][:domain]
end

#get_domain_characteristics(domain) ⇒ Hash

Gets domain characteristics

Parameters:

  • domain (Symbol)

    The domain to get characteristics for

Returns:

  • (Hash)

    The domain characteristics



214
215
216
# File 'lib/equipment/consensus_engine/weight_calculator.rb', line 214

def get_domain_characteristics(domain)
  DOMAIN_CHARACTERISTICS[domain].dup
end

#get_profile(domain) ⇒ Hash

Gets the weight profile for a specific domain

Parameters:

  • domain (Symbol)

    The domain to get weights for

Returns:

  • (Hash)

    The weight profile for the domain

Raises:

  • (ArgumentError)


110
111
112
113
114
115
116
# File 'lib/equipment/consensus_engine/weight_calculator.rb', line 110

def get_profile(domain)
  base_profile = @profiles[domain]
  raise ArgumentError, "Unknown domain: #{domain}" unless base_profile

  # Apply custom overrides
  base_profile.merge(@custom_overrides).merge(domain: domain)
end

#list_domainsArray<Symbol>

Lists all available domains

Returns:

  • (Array<Symbol>)

    Array of available domains



220
221
222
# File 'lib/equipment/consensus_engine/weight_calculator.rb', line 220

def list_domains
  %i[factual emotional sensitive creative balanced technical social business personal maritime]
end

#set_profile(domain, weights) ⇒ Object

Sets a custom weight profile for a domain

Parameters:

  • domain (Symbol)

    The domain to set

  • weights (Hash)

    The weights to apply

Raises:

  • (ArgumentError)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/equipment/consensus_engine/weight_calculator.rb', line 121

def set_profile(domain, weights)
  current = @profiles[domain]
  raise ArgumentError, "Unknown domain: #{domain}" unless current

  # Normalize weights to sum to 1
  raw_pathos = weights[:pathos_weight] || current[:pathos_weight]
  raw_logos = weights[:logos_weight] || current[:logos_weight]
  raw_ethos = weights[:ethos_weight] || current[:ethos_weight]
  total = raw_pathos + raw_logos + raw_ethos

  @profiles[domain] = {
    pathos_weight: raw_pathos / total,
    logos_weight: raw_logos / total,
    ethos_weight: raw_ethos / total,
    domain: domain,
    description: weights[:description] || current[:description],
    adjustment_rules: current[:adjustment_rules]
  }
end

#validate_profile(profile) ⇒ Hash

Validates a weight profile

Parameters:

  • profile (Hash)

    Profile to validate

Returns:

  • (Hash)

    Validation result { valid: Boolean, errors: Array<String> }



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/equipment/consensus_engine/weight_calculator.rb', line 268

def validate_profile(profile)
  errors = []

  if profile[:pathos_weight]
    if profile[:pathos_weight] < 0 || profile[:pathos_weight] > 1
      errors << 'pathos_weight must be between 0 and 1'
    end
  end

  if profile[:logos_weight]
    if profile[:logos_weight] < 0 || profile[:logos_weight] > 1
      errors << 'logos_weight must be between 0 and 1'
    end
  end

  if profile[:ethos_weight]
    if profile[:ethos_weight] < 0 || profile[:ethos_weight] > 1
      errors << 'ethos_weight must be between 0 and 1'
    end
  end

  if profile[:pathos_weight] && profile[:logos_weight] && profile[:ethos_weight]
    sum = profile[:pathos_weight] + profile[:logos_weight] + profile[:ethos_weight]
    if (sum - 1.0).abs > 0.001
      errors << "Weights must sum to 1, got #{sum.round(3)}"
    end
  end

  { valid: errors.empty?, errors: errors }
end