Robotics#
Human-robot interaction: order-aware human models for robots that ask questions and track trust.
HRI_DOMAINS: three question pairs a robot asks people, with illustrative population parameters (object clarification, trust and hand-over, preference elicitation).domain_models(): quantum-like, anchoring and Bayesian populations for a domain.estimate_unprimed_rates(): questioning designs for learning what people think before the robot’s own questions influence them (fixed order, reversed-order probe, split order).TRUST_PROTOCOL: hand-over outcomes and query designs for testing whether asking about trust changes trust.HumanModelEnsemble: competing human models weighted by evidence (BIC weights); gives the robot a predicted answer distribution and its uncertainty, which can be passed to an orchestrator as a confidence signal.ask_or_act(): decision rule for asking a person before acting.HumanModelService: middleware-independent service wrapping the ensemble (used by the ROS 2 node inintegrations/ros2).
The parameter values are illustrative (calibrated to answer rates of the size seen in survey data), not estimates from human-robot interaction studies. The simulation study that uses them is in the companion paper ‘Order-Aware Human Models for Robot Questioning and Trust’.
Classes
Competing human models weighted by evidence. |
|
Middleware-independent human-model service a robot can run next to its planner. |
Functions
Simulated populations for one domain. |
|
Estimate the unprimed "yes" rates from people who answer both questions. |
|
Decision rule for a robot that may ask a person before acting. |
|
Ask-or-act rule that scales with the hazard of the action and uses a lower confidence bound. |
- class HumanModelEnsemble(candidates=None, design=None)[source]#
Bases:
objectCompeting human models weighted by evidence.
The uncertainty is the entropy of the mixture prediction (bits) plus the disagreement between models (Jensen-Shannon divergence weighted by the model weights). A robot can use it to decide whether to ask, which question to ask first, and how much to trust an answer, and can pass it to an orchestrator as a confidence signal.
- Parameters:
- Variables:
fits (
listofFitResult) – Fits from the lastupdate(), best first.weights (
numpy.ndarray) – BIC weights of the fits.
Examples
>>> ens = HumanModelEnsemble() >>> ens.update({'AB': [40, 10, 20, 30], 'BA': [30, 20, 10, 40]}) >>> p, unc = ens.predict('AB')
- update(data, restarts=8, rng=None)[source]#
Fit every candidate model and compute BIC weights.
- Parameters:
data (
dict) – Answer counts{'AB': [yy, yn, ny, nn], 'BA': [...]}.restarts (
int, optional) – Restarts per fit.rng (
numpy.random.Generator, optional) – Random number generator.
- Returns:
HumanModelEnsemble–self.
- predict(condition)[source]#
Mixture prediction and its uncertainty.
- Parameters:
condition (
str) – Condition, for example'AB'.- Returns:
prediction (
numpy.ndarray) – Weighted mixture of the models’ predictions.uncertainty (
dict) –entropy_bits,model_disagreement_bits(weighted Jensen-Shannon divergence) andtotal_bits.
- class HumanModelService(candidates=None, refit_every=20, min_answers=20, restarts=4, seed=0)[source]#
Bases:
objectMiddleware-independent human-model service a robot can run next to its planner.
It accumulates people’s answers to two questions asked in either order, refits a
HumanModelEnsembleeveryrefit_everyanswers, and returns a prediction with its uncertainty and an ask-or-act decision. Messages are plain, JSON-friendly dicts. The ROS 2 node inintegrations/ros2wraps this class.- Parameters:
candidates (
listoftype, optional) – Model classes of the ensemble.refit_every (
int, optional) – Number of new answers between refits.min_answers (
int, optional) – Answers needed before the first fit.restarts (
int, optional) – Restarts per fit.seed (
int, optional) – Seed of the fitting random number generator.
Examples
>>> from quantum_mind.applications.robotics import HumanModelService >>> svc = HumanModelService() >>> svc.add_answer({'order': 'AB', 'answers': [1, 0]}) # first answer, second answer (1 = yes) {'n_answers': 1, 'refitted': False} >>> svc.query({'order': 'AB'})['action'] # too little data yet 'ask'
- add_answer(msg)[source]#
Record one person’s answers.
- Parameters:
msg (
dict) –{'order': 'AB' or 'BA', 'answers': [first, second]}with 1 = yes and 0 = no, in the order asked.- Returns:
dict–{'n_answers': int, 'refitted': bool}.- Raises:
ValueError – If the message is malformed.
- query(msg=None)[source]#
Predict answers and decide whether to ask.
- Parameters:
msg (
dict, optional) –{'order': 'AB', 'ask_cost': 1.0, 'error_cost': 5.0, 'max_disagreement_bits': 0.05}(all keys optional).- Returns:
dict–prediction[yy, yn, ny, nn],p_first_yes,uncertainty,weightsand theask_or_act()fields. Before enough answers have arrived,actionis'ask'with the reason “not enough data”.- Raises:
ValueError – If the order is not
'AB'or'BA'.
- estimate_unprimed_rates(design, generator, n, rng=None, model=None, probe=0.1)[source]#
Estimate the unprimed “yes” rates from people who answer both questions.
The unprimed rate of a question is its “yes” rate when it is asked first, before the other question can influence the answer.
- Parameters:
design (
{'fixed', 'probe', 'split'}) –'fixed': everyone answers A then B, and the B rate is read from the second answers (ignores order effects).'probe': a fractionprobeanswers B first, andmodelfitted to all answers gives both rates.'split': half answer each order and each rate comes from first answers only (model-free; the robust default).generator (
Model) – Population that produces the answers (for example fromdomain_models()).n (
int) – Number of people.rng (
numpy.random.Generator, optional) – Random number generator.model (
type, optional) – Model class fitted in the'probe'design.probe (
float, optional) – Fraction asked in the reversed order in the'probe'design.
- Returns:
- ask_or_act(p_success, uncertainty=None, ask_cost=1.0, error_cost=5.0, max_disagreement_bits=0.05)[source]#
Decision rule for a robot that may ask a person before acting.
Acting costs
error_cost * (1 - p_success)in expectation; asking costsask_costand is assumed to resolve the doubt. The robot also asks when the human models disagree by more thanmax_disagreement_bits, because thenp_successitself is unreliable. The rule is framework-agnostic: call it from a ROS 2 node, a behaviour tree or a planner.- Parameters:
p_success (
float) – Probability that acting now is right (for example the ensemble’s predicted “yes” rate for the robot’s current hypothesis).uncertainty (
dict, optional) – Output ofHumanModelEnsemble.predict(); itsmodel_disagreement_bitsis used.ask_cost (
float, optional) – Cost of asking.error_cost (
float, optional) – Cost of acting wrongly.max_disagreement_bits (
float, optional) – Model disagreement above which the robot always asks.
- Returns:
dict–action('ask'or'act'),expected_cost_actand a human-readablereason.- Raises:
ValueError – If
p_successis not in [0, 1].
Examples
>>> from quantum_mind.applications.robotics import ask_or_act >>> ask_or_act(0.9, ask_cost=1.0, error_cost=5.0)['action'] 'act' >>> ask_or_act(0.6, ask_cost=1.0, error_cost=5.0)['action'] 'ask'
- risk_aware_ask_or_act(p_success, hazard='medium', ask_cost=1.0, p_lower=None, uncertainty=None, max_disagreement_bits=0.05, max_risk=None)[source]#
Ask-or-act rule that scales with the hazard of the action and uses a lower confidence bound.
Handing over a cup and handing over a knife need different thresholds. The cost of a wrong action is taken from the hazard level, and when a lower bound on the success probability is available (for example from
CalibrationMonitoror a conformal predictor) the decision uses it instead of the point estimate, so an unreliable confidence makes the robot ask.- Parameters:
p_success (
float) – Estimated probability that acting now is right.hazard (
strorfloat, optional) – A key ofHAZARD_COSTS('low','medium','high','critical') or a numeric cost of a wrong action.ask_cost (
float, optional) – Cost of asking.p_lower (
float, optional) – Lower confidence bound on the success probability; used in place ofp_successwhen given.uncertainty (
dict, optional) – Output ofHumanModelEnsemble.predict(); disagreement between human models forces asking.max_disagreement_bits (
float, optional) – Disagreement threshold.max_risk (
float, optional) – Hard limit on the failure probability: above it the robot asks whatever the costs.
- Returns:
dict– The fields ofask_or_act(), plushazard_costandp_used.
Examples
>>> from quantum_mind.applications.robotics import risk_aware_ask_or_act >>> risk_aware_ask_or_act(0.95, 'low')['action'] # cup: act 'act' >>> risk_aware_ask_or_act(0.95, 'high')['action'] # knife: ask 'ask'