use crate::engine::SymbolicAnswer;
use crate::event_log::EventLog;
use crate::solver_handlers::finalize_simple;
pub fn try_incompatible_units(
prompt: &str,
normalized: &str,
log: &mut EventLog,
) -> Option<SymbolicAnswer> {
let (unit_a, unit_b) = detect_incompatible_unit_pair(normalized)?;
let (dim_a, dim_b) = (dimension_of(unit_a), dimension_of(unit_b));
log.append(
"unit_incompatibility",
format!("{unit_a}:{dim_a} vs {unit_b}:{dim_b}"),
);
let body = format!(
"{unit_a} measures {dim_a}; {unit_b} measures {dim_b}. \
These are different physical dimensions and cannot be converted into each other. \
The incompatibility is recorded as a `unit_incompatibility` link in the network."
);
Some(finalize_simple(
prompt,
log,
"unit_incompatibility",
"response:unit_incompatibility",
&body,
1.0,
))
}
const LENGTH_UNITS: &[&str] = &[
"meter",
"metre",
"meters",
"metres",
"km",
"kilometer",
"kilometre",
"cm",
"centimeter",
"centimetre",
"mm",
"millimeter",
"millimetre",
"метр",
"метра",
"метров",
"километр",
"сантиметр",
"миллиметр",
];
const DATA_UNITS: &[&str] = &[
"byte",
"bytes",
"kilobyte",
"kilobytes",
"kb",
"megabyte",
"megabytes",
"mb",
"gigabyte",
"gigabytes",
"gb",
"terabyte",
"terabytes",
"tb",
"bit",
"bits",
"байт",
"байта",
"байтов",
"килобайт",
"мегабайт",
"гигабайт",
"терабайт",
];
const MASS_UNITS: &[&str] = &[
"kilogram",
"kilograms",
"kg",
"gram",
"grams",
"pound",
"pounds",
"килограмм",
"грамм",
];
const TIME_UNITS: &[&str] = &[
"second",
"seconds",
"minute",
"minutes",
"hour",
"hours",
"секунда",
"секунды",
"секунд",
"минута",
"минуты",
"минут",
"час",
"часа",
"часов",
];
const TEMPERATURE_UNITS: &[&str] = &[
"celsius",
"fahrenheit",
"kelvin",
"цельсий",
"фаренгейт",
"кельвин",
];
fn dimension_of(unit: &str) -> &'static str {
if LENGTH_UNITS.contains(&unit) {
return "length";
}
if DATA_UNITS.contains(&unit) {
return "data storage";
}
if MASS_UNITS.contains(&unit) {
return "mass";
}
if TIME_UNITS.contains(&unit) {
return "time";
}
if TEMPERATURE_UNITS.contains(&unit) {
return "temperature";
}
"unknown"
}
fn detect_incompatible_unit_pair(normalized: &str) -> Option<(&'static str, &'static str)> {
let all_units: &[(&[&str], &'static str)] = &[
(LENGTH_UNITS, "length"),
(DATA_UNITS, "data storage"),
(MASS_UNITS, "mass"),
(TIME_UNITS, "time"),
(TEMPERATURE_UNITS, "temperature"),
];
let mut found: Vec<(&'static str, &'static str)> = Vec::new();
for (units, dim) in all_units {
for unit in *units {
if normalized.contains(unit) && !found.iter().any(|(_, d)| d == dim) {
found.push((unit, dim));
}
}
}
if found.len() < 2 {
return None;
}
let (unit_a, dim_a) = found[0];
let (unit_b, dim_b) = found[1];
if dim_a == dim_b {
return None;
}
Some((unit_a, unit_b))
}