Expected Parrot · A mathematical and practical tutorial

Morphological Analysis

From structured possibility spaces and cross-consistency logic to parallel digital-twin scoring, Pareto frontiers, and adaptive Bayesian search.

01 Orientation

General Morphological Analysis (GMA) explores problems whose important choices are discrete, interdependent, and not adequately represented by one smooth equation. A product, service, policy, or architecture is decomposed into dimensions; a complete configuration chooses exactly one value from every dimension.

c = (v1, v2, …, vd),   vi ∈ ViA configuration c chooses one value from each of d dimensions.

The method deliberately separates possibility, preference, evidence, and decision:

Possibility

What choices exist, and which combinations are internally coherent?

Preference

Which coherent combinations perform well for stakeholders and criteria?

Evidence

Which configurations should be assessed first when evaluation is costly?

Decision

Which tradeoffs and portfolio of concepts should move forward?

The governing discipline. Build the design space first, judge compatibility second, and evaluate attractiveness third. An unattractive pair is not necessarily incompatible; a fashionable option is not necessarily coherent.
Define dimensionsand valuesAssess cross-consistencyGenerate feasibleconfigurationsSample or scorein parallelCompare tradeoffsand portfolios
Zwicky keeps the local audit trail. The calling agent runs EDSL jobs and writes the final report.

02 The morphological box

Let dimension i have a finite value set Vi with size mi. Before consistency constraints, the configuration count is the Cartesian product:

|Ω| = ∏i=1d mi

Four dimensions with three values each produce 34=81 configurations. Ten dimensions with five values each produce 510=9,765,625. Combinatorial growth is the phenomenon the method makes visible.

Good dimensionValuesWhy it belongs
Delivery channelmobile, web, assistedEach is a mutually exclusive design choice.
Pricing modelsubscription, usage, bundledChanges the commercial architecture.
Trust mechanismhuman review, audit log, guaranteeExposes a consequential hidden assumption.
Not: desirabilitylow, medium, highDesirability evaluates configurations; it is not part of their morphology.
zwicky init hot-dog --problem "Design a differentiated hot-dog menu concept"

zwicky -C hot-dog dim add "Bun" --values "Classic,Pretzel,Gluten free"
zwicky -C hot-dog dim add "Sausage" --values "Beef,Chicken,Veggie"
zwicky -C hot-dog dim add "Topping" --values "Onions,Chili,Slaw"
zwicky -C hot-dog dim add "Service style" \
  --values "Street cart,Fast casual,Premium plated"
Agent checkpoint. Run zwicky -C <project> guide early and repeatedly. It returns the phase, quality checks, interaction rules, and next command.

03 Cross-consistency assessment

Cross-consistency assessment (CCA) judges pairs of values from different dimensions. OK records coherence, tension records a possible but risky pairing, and incompatible removes every configuration containing a hard contradiction.

P = Σi<j mimjThe number of cross-dimension value pairs available for judgment.

With four three-valued dimensions, P=6×9=54 cells. Same-dimension pairs are irrelevant because a configuration never selects two values from one dimension.

How names become command IDs

Zwicky generates stable IDs when dimensions and values are added. It lowercases the visible name, replaces each run of non-alphanumeric characters with a hyphen, and removes leading or trailing hyphens. A value’s full ID is its dimension ID, a period, and its value slug:

value_id = slug(dimension name) + "." + slug(value name)
Visible dimensionDimension IDVisible valueFull value ID
BunbunGluten freebun.gluten-free
SausagesausageVeggiesausage.veggie
ToppingtoppingChilitopping.chili
Service styleservice-styleStreet cartservice-style.street-cart

Use dim list to discover the stored names and IDs. A bare value name such as Veggie also works when it is unambiguous, but full IDs are safer in scripts and audit trails.

zwicky -C hot-dog dim list

# Full IDs are explicit and stable:
sausage.veggie
topping.chili
bun.gluten-free
service-style.street-cart
zwicky -C hot-dog cca set sausage.veggie topping.chili \
  --verdict incompatible --reason "The house chili contains beef."

zwicky -C hot-dog cca set bun.gluten-free service-style.street-cart \
  --verdict tension --reason "Separate handling is difficult in a compact cart."

zwicky -C hot-dog cca gaps
zwicky -C hot-dog cca plot --output writeup/cca.svg --mode assessment
Every white or colored square is an actual cross-value cell. Gray blocks are same-dimension or duplicate comparisons. Hover over a judgment for its recorded reason.

Reserve incompatible for combinations that cannot coherently coexist. Costly, unusual, or difficult pairs belong under tension or later preference scoring.

04 Feasible configurations

F = {c ∈ Ω : no pair in c belongs to I}I is the set of incompatible value pairs.

Zwicky can materialize F with early pruning: as soon as a partial configuration contains an incompatible pair, its remaining branch is abandoned. Materialization means constructing the surviving records in memory and writing them to .zwicky/configs.jsonl.

Materialization limit. Zwicky generates at most 100,000 configurations. It reads one record beyond the requested limit to detect overflow and writes nothing when the limit is exceeded. Larger spaces remain available through implicit sampling.
zwicky -C hot-dog config generate
# Optional lower ceiling; the hard ceiling is always 100,000:
zwicky -C hot-dog config generate --max-configs 10000

zwicky -C hot-dog config stats
zwicky -C hot-dog config list --human

In the hot-dog box, Veggie with beef-containing Chili eliminates every combination containing both. The other two dimensions remain free:

|F| = 34 − 32 = 81 − 9 = 72

With overlapping incompatible pairs, subtraction is not generally additive. Enumeration with pruning is safer than informal inclusion–exclusion.

05 Representing complete configurations

A configuration begins as a list of morphological value IDs, but evaluators need a stable presentation of the complete option. Build that presentation once and reuse it across rating jobs, pairwise comparisons, human surveys, and reports. Otherwise wording or imagery can change between evaluations and become an unrecorded experimental variable.

Canonical descriptions and writeups

Keep a compact factual description for survey presentation and a richer writeup for interpretation. Both should be derived from the same configuration record:

Evaluation description

Pretzel bun · Chicken sausage · Slaw · Premium plated
Price: $8

Short, parallel, and suitable for repeated scoring.

Concept writeup

Plated pretzel chicken dog

A chicken sausage served in a pretzel bun with slaw in a premium plated format. The concept combines an approachable protein with a substantial bun and restaurant-style presentation.

Use the short description when the task is to compare attributes. Use the writeup when evaluators need context such as use occasion, service assumptions, implementation details, or a concept name. Store the configuration ID alongside both so evidence can always be joined back to the morphological box.

EDSL can generate the fuller writeups in parallel from the same configuration ScenarioList. Ask for factual synthesis rather than a score, and keep the requested fields stable:

from edsl import QuestionFreeText, Survey

writeup = QuestionFreeText(
    question_name="concept_writeup",
    question_text="""Write a concise concept card for this configuration.

Configuration ID: {{ scenario.config_id }}
Values: {{ scenario.description }}

Return a short concept name followed by two factual sentences describing
the complete offering, intended occasion, and service format. Do not rate it.""",
)

writeup_results = Survey([writeup]).by(configuration_scenarios).run()
writeup_results.git.save("hot-dog/option-writeups.ep")

Ingest the returned text into Zwicky’s presentation registry. The run remains keyed by configuration ID and preserves the source Results package:

zwicky -C hot-dog presentations ingest \
  --results hot-dog/option-writeups.ep \
  --name "Hot-dog concept writeups"

zwicky -C hot-dog presentations list
zwicky -C hot-dog presentations show <presentation-run-id>

Use the stored text in a real evaluation by passing its run ID. Zwicky checks that the run covers every selected configuration and then places the saved title, description, and writeup into each assessment Scenario:

zwicky -C hot-dog utility build \
  --sample <sample-id> \
  --presentation <presentation-run-id>

zwicky -C hot-dog preference build <preference-design-id> \
  --presentation <presentation-run-id>

The generated writeup is now reusable presentation material, not evaluation evidence itself. Ratings and choices collected after it is attached are the evidence.

Generate one image per option

When appearance matters, create one canonical image for each configuration and reuse it wherever that option appears. The prompt should hold camera, scale, background, lighting, and exclusions constant while substituting only the configuration description:

from edsl import QuestionImageGeneration

make_image = QuestionImageGeneration(
    question_name="configuration_image",
    question_text=(
        "Create a consistent studio product photograph of this hot dog: "
        "{{ scenario.description }}. Neutral background, identical camera "
        "angle and scale; no text, labels, prices, logos, hands, or people."
    ),
)

image_results = make_image.by(configuration_scenarios).run()
image_results.git.save("hot-dog/option-images.ep")
Generated pretzel-bun veggie hot dog with slaw

Pretzel · Veggie · Slaw · Premium plated

Generated gluten-free-bun veggie hot dog with onions

Gluten free · Veggie · Onions · Premium plated

Two actual images from the registered 12-option hot-dog generation run. The same assets are reused in the Humanize comparison shown in Chapter 9.

Register generated assets with Zwicky

zwicky -C hot-dog images ingest \
  --results hot-dog/option-images.ep \
  --name "Hot-dog option renders"

zwicky -C hot-dog images list
zwicky -C hot-dog images show <image-run-id>
zwicky -C hot-dog images export <image-run-id>

Zwicky stores unique image bytes by SHA-256 hash, indexes their configuration mappings, and preserves the original EDSL Results package and run manifest. The registry is canonical; images export creates a self-contained EDSL ScenarioList.ep only when an evaluation job needs one.

Presentation is reusable study infrastructure. A configuration ID, concise description, fuller writeup, price, and optional image should travel together. Rating and comparison methods can then change without silently changing what the evaluator saw.

06 Sampling designs

If every feasible configuration can be scored cheaply, exhaustive evaluation is clearest. Sampling matters when configurations, twins, criteria, rationales, or model calls make exhaustive scoring expensive.

A sampling design is a rule for deciding which configurations receive the evaluation budget. This chapter covers three ways to construct an initial batch before scores exist. Bayesian follow-up sampling begins only after results exist and is developed separately in Chapters 13–15.

MethodOptimizesUse whenMain sacrifice
randomUnbiased reproducibilityYou need a simple baseline.May miss rare values or pairs.
coverageValue-pair representationYou need an intuitive breadth guarantee.Not optimized for model estimation.
d-optimalSeparating the effects in a chosen modelYou intend to fit main or pairwise effects.Depends on the model you specify.

Run the three designs

1. Random: draw a neutral baseline

Random sampling gives every feasible configuration the same chance of selection. The seed makes the draw reproducible. For the 72 feasible hot dogs, request 12 concepts:

zwicky -C hot-dog sample create \
  --method random --size 12 --seed 123 --human

The command returns the immutable sample ID, selected configurations, and diagnostics. The abridged output from the worked example is:

id: sample-72e01dc5
method: random
size: 12
seed: 123
theoretical_count: 81
attempts: 14
accepted: 12
acceptance_rate: 0.857143

The sampler drew 14 distinct Cartesian indices, rejected two infeasible combinations, and retained 12. It did not optimize which values or pairs appeared.

2. Coverage: spend the batch on breadth

Coverage sampling first draws a feasible candidate pool, then greedily selects the configuration that adds the most previously unseen values and cross-dimension value pairs. For this small example, a pool of 72 exposes the full feasible space:

zwicky -C hot-dog sample create \
  --method coverage --size 12 \
  --candidate-pool 72 --seed 123 --human
id: sample-575bfdf9
method: coverage
size: 12
candidate_count: 72
values_covered: 12 of 12
pairs_covered: 53 of 53
pair_coverage: 1.0
attempts: 81
accepted: 72

Twelve selected hot dogs exercise every individual value and every feasible cross-dimension pair visible in the 72-concept pool. Repeating a covered pair provides no additional coverage gain, so the method favors breadth early.

3. D-optimal: choose informative contrasts

D-optimal sampling chooses configurations that help distinguish the coefficients in a named feature model. If Veggie always appears with Gluten-free, their effects are confounded; the design instead varies them independently across the batch. Here the initial model contains main effects only:

zwicky -C hot-dog sample create \
  --method d-optimal --features main-effects \
  --candidate-pool 72 --prior-precision 1 \
  --size 12 --seed 123 --human
Id: sample-360be9d3
Method: d-optimal
Feature Model: main-effects
Size: 12
feature count: 13
estimable rank: 9
rows per feature: 0.9231
regularized log determinant gain: 15.7103
values covered: 12 of 12
pairs covered: 53 of 53

The design selected 12 rows for a 13-feature categorical encoding. The feasible box has estimable rank 9 because one value is selected from every dimension and some columns are linearly dependent. Prior precision 1 regularizes those dependencies.

Put the feature row for each selected configuration into a matrix X. D-optimal design chooses rows that maximize the volume of the regularized information matrix:

S* = arg max|S|=n log det(αI + XSTXS)

A larger determinant means the selected rows provide broader, less redundant contrasts for the specified feature model. Zwicky builds the batch greedily, adding the candidate with the largest incremental information gain:

Δ(x) = log(1 + xTA−1x)

This is an initial-design calculation: it uses configuration features, not observed outcome scores. The --features choice determines what the design is trying to estimate, and α is set by --prior-precision.

The hot-dog box under each design

Each panel below contains the same 81 positions: nine Bun × Sausage groups, each containing the nine Topping × Service-style combinations. The nine white slashed cells are Veggie + Chili combinations removed by cross-consistency analysis. The remaining 72 gray cells are feasible; green cells are the 12 configurations returned by the command above. Hover over any cell for its complete configuration.

Selected for evaluationFeasible, not selectedIncompatible
Three different 12-configuration views of the same 72-concept feasible universe.

The visual difference is the design decision. Random preserves a probability sample. Coverage deliberately spreads selections across the box. D-optimal chooses contrasts that support the specified feature model. In this small balanced example, both optimized designs achieve complete feasible pair coverage; in larger boxes their objectives can lead to different trade-offs.

Sampling without enumerating

Zwicky treats the Cartesian space as a mixed-radix index. It draws an integer J uniformly from 0…|Ω|−1, decodes J into one value index per dimension, and rejects the draw if it contains an incompatible pair. Because the original Cartesian draw is uniform, conditioning on feasibility produces a uniform feasible draw:

P(C=c | C∈F)=1/|F|   for every c∈F

Indices are not repeated, so accepted configurations are unique. The sampler reports attempts, acceptance rate, theoretical Cartesian count, exclusions, and whether the Cartesian space was exhausted. A sparse feasible region may require a larger attempt budget.

zwicky sample create --method random --size 40 --seed 123
zwicky sample create --method coverage --size 40 \
  --candidate-pool 2000 --max-attempts 200000 --seed 123
zwicky sample create --method d-optimal \
  --features main-plus-pairwise --candidate-pool 10000 \
  --size 100 --seed 123
zwicky sample stats sample-123 --human

Random sampling selects directly from accepted implicit draws. Coverage and D-optimal methods first draw a bounded feasible candidate pool and then optimize within that pool. Their result is therefore conditional on the pool; increasing --candidate-pool improves search breadth while increasing time and memory.

The choice between exhaustive scoring and sampling depends on evaluation cost. When ten thousand scores are inexpensive, exhaustive evaluation may be simpler; higher per-configuration costs make sampling more valuable.

07 Parallel digital-twin scoring

After defining and sampling the feasible design space, we still need evidence about which complete configurations may work well. In this workflow, we ask AI-generated synthetic personas to evaluate them. Each persona is instructed to answer from a specified stakeholder perspective—for example, a price-sensitive customer, a street-cart operator, or a traditional hot-dog buyer. We call these simulated evaluators digital twins.

What Expected Parrot and EDSL do

Expected Parrot develops tools for research with AI agents and human respondents. Its open-source Expected Parrot Domain-Specific Language (EDSL) is a Python framework for defining questions, surveys, personas, language models, scenarios, and reproducible results. Zwicky designs the morphological assessment; EDSL turns that design into executable AI interviews.

EDSL objectMeaning in this tutorialHot-dog example
AgentOne synthetic respondent. Its traits or persona tell the language model whose perspective to simulate.“A budget-conscious commuter buying lunch from a street cart.”
AgentListA collection of agents evaluated together. It may be created from Zwicky stakeholders or imported from an existing .ep package.Twenty commuter personas plus ten food-service operator personas.
ScenarioThe changing context inserted into otherwise identical questions. Zwicky makes each complete configuration a scenario.Classic bun + Veggie sausage + Onions + Street cart.
QuestionA typed prompt with a validated answer format, such as a 1–7 scale or free text.Purchase intent on a seven-point scale.
SurveyThe set of criterion and rationale questions asked for every scenario.Purchase intent, novelty, complexity, and reasons.
Jobs packageThe executable combination of a Survey, AgentList, ScenarioList, and language model settings. EDSL expands it into individual AI interviews.All selected personas × all sampled hot dogs.
ResultsThe structured responses plus provenance such as agent, scenario, question, and model.One persona’s scores and explanations for one hot dog.

An .ep file is a saved EDSL artifact. It is not a prose prompt pasted into a chat window: it is a reusable package describing the agents, questions, scenarios, or executable jobs so the assessment can be inspected, run, saved, and analyzed consistently.

What question does an AI persona answer?

First define criteria with questions that a respondent can answer from the information shown. Zwicky inserts the complete configuration description beneath each criterion question. For example:

Question as presented for one interview

Stakeholder description: A budget-conscious commuter who buys quick weekday lunches.

Question: How likely would you be to purchase this configuration?

Configuration ID: config-a1b2c3d4

Values:
• Pretzel
• Veggie
• Slaw
• Street cart

Known tensions:
• No recorded tensions.

Answer: Select 1–7, where 1 is very low and 7 is very high.

Follow-up: Explain your Purchase intent rating. Name the main drivers and tradeoffs.

Zwicky represents that interview with ordinary EDSL objects. The following abbreviated Python shows the generated question text and object relationships:

from edsl import (
    Agent, AgentList, Jobs,
    QuestionFreeText, QuestionLinearScale,
    Scenario, ScenarioList, Survey,
)

agents = AgentList([
    Agent(
        name="budget-commuters",
        traits={
            "stakeholder_id": "budget-commuters",
            "stakeholder_name": "Budget commuters",
            "stakeholder_description": (
                "Budget-conscious commuters who buy quick weekday lunches."
            ),
            "stakeholder_kind": "customer segment",
        },
        instruction=(
            "You are evaluating product or feature configurations from "
            "the perspective of the stakeholder described in your traits."
        ),
    )
])

configurations = ScenarioList([
    Scenario({
        "config_id": "config-a1b2c3d4",
        "config_description": (
            "Configuration ID: config-a1b2c3d4\n\n"
            "Values:\n- Pretzel\n- Veggie\n- Slaw\n- Street cart\n\n"
            "Known tensions:\n- No recorded tensions."
        ),
    })
])

purchase_intent = QuestionLinearScale(
    question_name="purchase_intent",
    question_text=(
        "How likely would you be to purchase this configuration?\n\n"
        "{{ config_description }}"
    ),
    question_options=[1, 2, 3, 4, 5, 6, 7],
    option_labels={1: "very low", 7: "very high"},
    include_comment=True,
)

purchase_reason = QuestionFreeText(
    question_name="rationale_purchase_intent",
    question_text=(
        "Explain your Purchase intent rating. "
        "Name the main drivers and tradeoffs.\n\n"
        "{{ config_description }}"
    ),
)

survey = Survey(
    [purchase_intent, purchase_reason],
    name="zwicky_configuration_utility",
)

jobs = Jobs(
    survey=survey,
    agents=agents,
    scenarios=configurations,
)

The {{ config_description }} placeholder is filled from each Scenario at execution time. Adding scenarios repeats the same questions for every selected configuration; adding agents repeats them for every persona. The Jobs object is therefore the complete executable study design.

The persona, question wording, scale anchors, and configuration description define the evaluation context. “How likely would you be to purchase this for a weekday lunch at the stated price?” identifies a perspective, behavior, and occasion. Include price as a dimension or scenario field when the question refers to it.

Customizing the evaluation wording

The text supplied to criteria add --question is used verbatim as the primary valuation question. Zwicky supplies defaults for the shared agent instruction, rationale question, and scale endpoint labels. Each can be overridden when building the assessment:

zwicky -C hot-dog utility build \
  --sample sample-123 \
  --criteria purchase-intent \
  --instruction "Evaluate each concept as a weekday lunch purchase." \
  --rationale-question "What primarily explains your {criterion} score?" \
  --low-label "Definitely would not buy" \
  --high-label "Definitely would buy"

{criterion} expands to the criterion’s display name, so the example becomes “What primarily explains your Purchase intent score?” The configuration description is appended automatically. These resolved settings are saved in the assessment manifest and contribute to its ID; two assessments with different wording are separate artifacts.

How the scoring experiment is assembled

  1. Register perspectives. Add stakeholder descriptions or import a previously constructed EDSL AgentList. Several agents per segment can represent varied synthetic personas; repeating an identical vague persona is not equivalent to recruiting more people.
  2. Select configurations. Use all feasible configurations when affordable, or a random, coverage, D-optimal, or adaptive sample.
  3. Define criteria. Each criterion supplies a question, direction (maximize or minimize), and optional weight.
  4. Build artifacts. Zwicky writes the AgentList, ScenarioList, Survey, and one or more Jobs packages.
  5. Run AI interviews. EDSL sends the appropriate persona, question, and configuration to a language model and records the structured response.
  6. Ingest and analyze. Zwicky joins responses back to configuration and stakeholder IDs, checks completion, computes criterion summaries, and retains rationales and disagreement.
interviews = N ΣpAp    and    scores = N ΣpApKpPanel p has Ap evaluators and Kp assigned criteria; N configurations are evaluated.

Evaluator assignment is criterion-specific. Consumer personas can answer purchase intent and novelty together, while a food-service expert answers operational cost once for each configuration. Zwicky groups criteria sharing an evaluator panel into one survey and returns a separate edsl run command for each panel.

zwicky -C hot-dog stakeholders add \
  --name "Traditionalists" \
  --description "Buyers who prefer familiar combinations and value." \
  --kind "digital twin segment"

zwicky -C hot-dog utility build \
  --all-configs \
  --criteria purchase-intent,operational-cost,novelty \
  --rationale none --batch-size 250

utility build does not call a language model. It creates the assessment packages and returns commands for running them. A batch size of 250 places at most 250 configuration scenarios in each independently runnable shard. Sharding makes large runs easier to parallelize, retry, and ingest incrementally; it does not change the questions or scoring logic.

The execution handoff: edsl run

The returned run_commands contain independently runnable shards:

edsl run jobs-0001.ep --output results-0001.ep
edsl run jobs-0002.ep --output results-0002.ep

zwicky utility ingest utility-123 \
  --results results-0001.ep results-0002.ep
zwicky utility analyze utility-123
edsl run is the execution step. The preceding Zwicky commands modify local project state and assemble the study. Running edsl run jobs-0001.ep loads the saved agents, scenarios, and survey; selects the configured or default language model; executes the AI interviews; and writes an EDSL Results package. This step requires the relevant EDSL/Expected Parrot or model-provider credentials and can consume inference credits or incur model-provider cost.

The --output results-0001.ep argument gives the completed Results package an explicit path. Zwicky does not execute this command automatically: the person or calling agent running the study controls model selection, credentials, execution mode, retries, and timing. Once every shard has a result package, zwicky utility ingest imports them and zwicky utility analyze calculates the comparisons.

How ratings become comparisons

On a seven-point maximize criterion such as purchase intent, 1 means very low and 7 means very high. On a minimize criterion such as operational complexity, the response scale describes increasing complexity, so Zwicky reverses it for composite summaries: a raw 2 becomes an oriented 6. Raw scores remain available. Zwicky then reports means by configuration and stakeholder, disagreement, completion, value-level patterns, rationales, and—when several criteria are present—Pareto trade-offs.

The analysis includes the number and diversity of agents, completion rates, dispersion across personas, model and prompt provenance, and written rationales. Consistent questions and evaluation conditions make configurations directly comparable; replication helps characterize small score differences.

For a large first-pass screen use --rationale none to reduce token use and latency. Reassess a smaller set of finalists with --rationale all; the explanations can reveal missing assumptions, unexpected interactions, and reasons that an average score conceals.

08 Pairwise study design and price

Direct ratings ask each evaluator to place one configuration on a scale. A pairwise task instead presents two complete configurations at stated prices and asks which one the evaluator would choose. The comparison supplies a sharper behavioral contrast: choosing A means that A’s complete bundle is preferred to B’s complete bundle under the prices shown.

Use ratings for levels

“How operationally complex is this?” or “How likely are you to purchase this?” Ratings support absolute thresholds, criterion summaries, and Pareto analysis.

Use choices for trade-offs

“Which would you purchase?” Choices reveal whether one bun, sausage, topping, service style, or price compensates for another.

What an evaluator sees

Option A
  • Pretzel bun
  • Veggie sausage
  • Slaw
  • Fast casual
$9
OR
Option B
  • Classic bun
  • Beef sausage
  • Onions
  • Street cart
$7
Option AOption BThey seem about the sameNeither
One comparison scenario. Prices vary independently across tasks, allowing the choice model to estimate how price trades off against morphological values.

They seem about the same records indifference: both offers may be acceptable, but neither is preferred. Neither instead means that neither offer clears the purchase threshold. Neither is included by default and is represented as an outside alternative with utility fixed at zero. Use --no-outside-option to remove Neither while retaining the indifference response.

Construct a bounded comparison design

Even 72 hot dogs create 2,556 unordered configuration pairs before price combinations. There is no need to ask every evaluator every pair. Zwicky draws a bounded candidate pool and greedily selects comparisons that balance appearances of configurations, morphological values, and price levels.

zwicky -C hot-dog preference design \
  --all-configs \
  --pairs 40 \
  --price-levels 6,8,10 \
  --evaluators traditionalists,adventurous-diners,health-conscious-diners \
  --seed 123 --human

The returned design records every A/B configuration, the price attached to each side, evaluator panel IDs, whether Neither is available, and balance diagnostics:

id: preference-design-2f31c7a8
design: balanced
configuration_count: 72
pair_count: 40
price_levels: [6, 8, 10]
outside_option: true
configurations_exercised: 58
min_config_appearances: 1
max_config_appearances: 2

The exact ID and diagnostics depend on the stored configurations and seed. --sample <sample-id> limits both alternatives to a previously constructed sample; --all-configs uses the feasible space without writing a quadratic list of every possible comparison.

Use persona stakeholders or a custom AgentList

--evaluators uses the same stakeholder registry as utility scoring. A stakeholder may be a Zwicky persona description or an imported EDSL AgentList. The latter is useful when the evaluator population has already been constructed with detailed traits, names, instructions, or segment structure:

zwicky -C hot-dog stakeholders add \
  --name "Buyer panel" \
  --description "Synthetic lunch buyers used for discrete choice." \
  --agent-list agent_list.ep

zwicky -C hot-dog preference design \
  --all-configs --pairs 40 --price-levels 6,8,10 \
  --evaluators buyer-panel --seed 123

Zwicky loads the agents from agent_list.ep into the comparison job. It does not replace them with one generated persona. Multiple evaluator panels can be named with a comma-separated list.

Build the exact EDSL study

zwicky -C hot-dog preference build preference-design-2f31c7a8 \
  --instruction "Choose as a weekday lunch buyer. Consider the complete offer and price." \
  --question "Which option would you be more likely to purchase for lunch?" \
  --human

The command writes agent_list.ep, scenario_list.ep, survey.ep, and jobs.ep. The multiple-choice question stored in the Survey is:

Which option would you be more likely to purchase for lunch?

OPTION A
- Pretzel
- Veggie
- Slaw
- Fast casual
- Price: $9

OPTION B
- Classic
- Beef
- Onions
- Street cart
- Price: $7

Options: Option A, Option B, They seem about the same, Neither
edsl run performs the evaluations. preference build only assembles and saves the study. Run the returned command in the calling agent’s EDSL environment, then give the Results package back to Zwicky.
edsl run .zwicky/preference/assessments/preference-a93e421c/jobs.ep \
  --output choice-results.ep

zwicky -C hot-dog preference ingest preference-a93e421c \
  --results choice-results.ep
zwicky -C hot-dog preference analyze preference-a93e421c

09 Eliciting preferences from real people

The designed comparison task is not limited to AI evaluators. EDSL Humanize turns the same alternatives, prices, response options, and ordering into a respondent-facing survey. Completed human responses return as EDSL Results and enter the same Zwicky ingestion and choice-model workflow.

Humanize survey showing two generated hot-dog options side by side with four response choices
The actual hot-dog Humanize survey: native FileStore images, configuration descriptions, Option A, Option B, indifference, and Neither presented in one responsive comparison.

Let people take the comparison survey

preference build also writes humanize.json. It contains the radio-button schema and responsive CSS used to render the Markdown alternatives as two product cards. The same Survey and ScenarioList can therefore be answered by people through EDSL Humanize:

# Check the schema against the generated Survey.
edsl humanize schema validate \
  --survey .zwicky/preference/assessments/preference-a93e421c/human_survey.ep \
  --schema .zwicky/preference/assessments/preference-a93e421c/humanize.json

# Inspect the layout before publishing.
edsl humanize preview \
  --survey .zwicky/preference/assessments/preference-a93e421c/human_survey.ep \
  --schema .zwicky/preference/assessments/preference-a93e421c/humanize.json

# Publish the expanded respondent survey.
edsl humanize create \
  --survey .zwicky/preference/assessments/preference-a93e421c/human_survey.ep \
  --schema .zwicky/preference/assessments/preference-a93e421c/humanize.json \
  --name "Hot-dog preference elicitation"

human_survey.ep is different from the one-question survey.ep used by AI Jobs. Zwicky has already expanded every pair scenario into its own question, so one respondent sees the complete designed sequence. No Humanize scenario-assignment option is needed. humanize create returns JSON containing an admin_url, preview_url, and respondent_url.

edsl humanize responses <human-survey-uuid> \
  --output human-responses.ep

zwicky -C hot-dog preference ingest preference-a93e421c \
  --results human-responses.ep
zwicky -C hot-dog preference fit preference-a93e421c

Humanize responses are saved as an EDSL Results package, so they enter the same Zwicky ingestion and choice-model path as AI evaluator responses. The scenario columns preserve the exact A/B values and prices shown in every choice.

Learn a person, a panel, or both

Elicitation goalDesignResult
Population preference modelInvite many respondents to a balanced set of comparisons.A pooled choice model and respondent/segment summaries.
Individual preference modelGive one respondent enough varied comparisons to estimate price and value trade-offs.Respondent-specific coefficients, willingness-to-pay estimates, and diagnostics.
Behavioral digital twinRetain that respondent’s observed choices and fitted preference profile; optionally pair them with separate background or open-text elicitation.An Agent definition can use the profile as structured traits or instructions, while the fitted choice model provides a quantitative behavioral twin.

Zwicky groups Humanize rows by respondent identifier when it is present. preference fit reports coefficients and willingness-to-pay separately for each respondent with enough completed choices, as well as for the pooled data. This supports two distinct handoffs: use the fitted coefficients directly to predict the person’s choices, or use their choice profile when constructing an EDSL Agent for later qualitative evaluation.

Worked Humanize result: one person, 36 choices, 72 predictions

The hot-dog elicitation was published as a 36-question Humanize survey and completed by one respondent. The response package contained one EDSL Results row with all 36 named answers. Zwicky expanded that row back into its designed pairs:

edsl humanize responses \
  11692194-f4da-4aa6-a9f6-e02a9c52a3b1 \
  --output human-responses.ep

zwicky -C hot-dog preference ingest preference-a542935b \
  --results human-responses.ep
zwicky -C hot-dog preference fit preference-a542935b \
  --features main-effects --prior-precision 1
Observed responseCount
Option A17
Option B16
They seem about the same3
Neither0

Because Neither was offered but never selected, Zwicky fitted the likelihood conditional on A versus B. This estimates price from differences between the two displayed prices; retaining an unchosen outside alternative would confound the absolute price level with the utility required for both offers to beat Neither. The conditional model converged in six iterations, achieved 84.9% in-sample accuracy on non-indifferent choices, and estimated a price coefficient of −0.065.

Open the human preference profile
The fitted profile favors Pretzel, Chicken, and Premium plated service. Topping effects were small: Slaw and Chili were slightly above Onions.

At a common $8 price, the top predicted configuration was Pretzel · Chicken · Slaw · Premium plated, followed by the same configuration with Chili and then Onions. The model predicts all 72 feasible hot dogs by recombining the learned categorical effects, even though the 36 pairs directly exercised 71 configurations.

Within-dimension coefficient contrasts imply approximately $4 more for Chicken than Beef and $2 more for Slaw than Onions. Larger estimates—about $22 for Pretzel over Classic and $16 for Premium plated over Street cart—mainly show that morphology dominated the relatively weak price response in this short exercise; the ordering is more stable than those exact dollar magnitudes.

The agent pattern for getting structured user input

  1. Build locally. Construct the balanced design and run preference build. Report the number of tasks and the attributes being learned.
  2. Publish externally. Run the returned humanize_create_command and parse its JSON response.
  3. Hand control to the user. Present data.respondent_url as a link and ask the user to reply when finished. End the turn while they answer.
  4. Resume from evidence. Download the completed Results with edsl humanize responses; check completion and response counts before fitting.
  5. Interpret the model. Report preference contrasts, price sensitivity, fit diagnostics, and ranked configurations. If more precision is useful, generate a smaller adaptive follow-up survey from the posterior.
Why use Humanize here? A long, structured elicitation is easier to complete and audit as one responsive survey than as 36 separate chat turns. The conversation still owns the handoff: it explains the task, provides the link, waits for the user, and interprets the returned evidence.

Several human respondents

The same Humanize respondent URL can collect a panel rather than one person. edsl humanize responses returns all completed respondents in one Results package. Zwicky identifies the response rows by their stable human/agent identifier, expands every respondent’s long survey into pair records, and reports:

  • respondent count and choices completed per respondent;
  • pooled coefficients and configuration predictions;
  • one preference profile per respondent with enough choices; and
  • completion against respondents × designed pairs, rather than against a fixed one-person denominator.

A pooled model answers what the panel tends to choose. Respondent-level models preserve heterogeneity and can become individual behavioral twins. Named segments can be analyzed by joining respondent metadata or assignment information before fitting a hierarchical extension.

10 Fitting and extending pairwise choice models

Once comparisons have been answered by AI evaluators, real respondents, or both, fit the relative effects of morphological values and price. This chapter also shows how stored visual assets enter image-enabled comparison jobs.

Using stored images in comparison surveys

Chapter 5 creates and registers canonical option descriptions, writeups, and images. For a comparison job, export the selected image run and join its configuration-keyed FileStores onto the designed A/B pairs:

zwicky -C hot-dog images export image-run-47871b01 \
  --output hot-dog/option-images.ep

The answer to each image-generation question is an EDSL FileStore. Put the FileStores themselves in the comparison Scenario; there is no separate base64 or image-URL conversion step:

pair = Scenario({
    "config_a": "fafa5014f31f",
    "description_a": "Pretzel bun, chicken sausage, slaw, premium plated",
    "image_a": image_a,                 # an EDSL FileStore
    "config_b": "a2112fa4870c",
    "description_b": "Classic bun, beef sausage, onions, street cart",
    "image_b": image_b,                 # an EDSL FileStore
})

question_text = """## Which option would you choose?

{{ scenario.image_a }}

{{ scenario.description_a }}

{{ scenario.image_b }}

{{ scenario.description_b }}"""

The same native representation supports two delivery paths:

EvaluatorHow images travelQuestion
Vision-capable modelEDSL recognizes the referenced FileStores and places the files in the model request.The multiple-choice question can combine images, text attributes, and prices.
Humanize respondentHumanize publishes the ScenarioList and renders each referenced FileStore as an .edsl-question-image.The long Humanize Survey retains the same A/B/indifferent/Neither answers.

Making the Humanize images side by side

Humanize separates question text at each FileStore placeholder. In the rendered DOM, the heading, image A, description A, image B, and description B become five sibling blocks. This means raw HTML around the placeholders is escaped, while a Markdown table receives empty cells because the images have been extracted from it. The working layout targets the emitted sibling blocks instead:

.edsl-question:has(.edsl-question-image) > div:first-child {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: 1.25rem;
}

/* Heading spans both columns. */
.edsl-question:has(.edsl-question-image)
  > div:first-child > div:nth-child(1) {
  grid-column: 1 / -1;
}

/* Image A and its description occupy the left column. */
.edsl-question:has(.edsl-question-image)
  > div:first-child > div:nth-child(2),
.edsl-question:has(.edsl-question-image)
  > div:first-child > div:nth-child(3) {
  grid-column: 1;
}

/* Image B and its description occupy the right column. */
.edsl-question:has(.edsl-question-image)
  > div:first-child > div:nth-child(4),
.edsl-question:has(.edsl-question-image)
  > div:first-child > div:nth-child(5) {
  grid-column: 2;
}

.edsl-question-image {
  width: auto;
  max-width: 100%;
  max-height: 42vh;
  margin: 0 auto;
  object-fit: contain;
}

The production example also assigns explicit grid rows, adds Option A and Option B labels with pseudo-elements, and collapses to one column below 640 pixels. Run it directly:

python examples/build_image_preference_humanize.py \
  --results hot-dog/preference-images-12.ep \
  --output-dir hot-dog/image-humanize \
  --publish \
  --name "Hot-dog image comparisons"

The builder passes {"survey": {"custom_css": ...}} as the humanize_schema to Jobs.humanize(..., scenario_list_method="loop"). The full responsive rules live in examples/humanize_image_comparison.css.

Images should be keyed by configuration ID, not pair ID. That requires 72 generations for the complete hot-dog box rather than two new generations for every comparison. A text-only control group can measure whether imagery changes the learned preferences; if it does, “presentation style” has become part of the experiment rather than neutral decoration.

Balanced pairs
EDSL choices
Choice model
Trade-offs
Adaptive pairs

The Bayesian choice model

Each alternative becomes a categorical feature vector x plus numeric price p. Its latent utility is a linear combination of morphological effects and price:

U(A) = xATβ + γpA     U(B) = xBTβ + γpB

With an outside option, its utility is fixed at zero. Choice probabilities use the softmax function:

Pr(A) = exp(U(A)) / [exp(U(A)) + exp(U(B)) + exp(0)]

Without Neither, the denominator contains only A and B; this is the Bradley–Terry/logistic form. An indifference answer contributes a fractional likelihood—half A and half B—so it pulls their fitted utilities together without treating the response as rejection. Zwicky places a zero-centered Gaussian prior on the coefficients. The prior regularizes sparse levels and makes uncertainty available for the next comparison round.

zwicky -C hot-dog preference fit preference-a93e421c \
  --features main-effects \
  --prior-precision 1.0 --human
Model outputInterpretation
Price coefficient γChange in latent utility for one currency unit of price. A negative estimate means higher prices reduce choice probability.
Morphological coefficients βJointly fitted contributions of buns, sausages, toppings, and service styles.
Approximate willingness to payFor feature j, −βj/γ converts its utility contribution into the price units used in the design.
Configuration predictionsPredicted share for each exercised configuration at the reported median test price.
Segment summariesChoice count, fitted price coefficient, accuracy, and log loss for each evaluator segment.
Posterior covarianceRemaining uncertainty about features and price, used to select informative follow-up pairs.

main-effects is the natural starting point. main-plus-pairwise adds interactions such as Pretzel × Slaw, but needs substantially more varied choices to estimate them.

Choose the next comparisons adaptively

After the first fit, adaptive design scores candidate comparisons by posterior information. Pairs receive high priority when the model is uncertain about their utility difference and predicts a choice near 50/50. These are the comparisons most capable of changing what the model has learned.

information(A,B) ≈ Pr(A)[1−Pr(A)] · Var[U(A)−U(B)]
zwicky -C hot-dog preference design \
  --all-configs \
  --pairs 20 \
  --price-levels 6,8,10 \
  --evaluators buyer-panel \
  --design adaptive \
  --model preference-model-61b84d2e \
  --seed 456

This begins a new EDSL round; it does not rescore every hot dog. Build, run, ingest, and refit using the same sequence. Direct ratings can continue alongside this workflow for absolute operational, cost, novelty, or safety criteria. Pairwise consumer choice supplies a different outcome: relative preference under explicit prices.

11 Multiple criteria

Dimensions describe; criteria evaluate

A morphological dimension is a choice used to construct a configuration: bun, sausage, topping, or service style. A criterion is a question used to evaluate the completed configuration: purchase intent, operational complexity, novelty, margin, accessibility, or deployment time. Dimensions define what a concept is; criteria measure how it performs.

This separation matters because the same value can help one objective and hurt another. Premium plated service might raise purchase appeal while also increasing operational complexity. Combining those judgments into the morphological box would hide the trade-off. Zwicky instead preserves one score per criterion and configuration.

configuration → one complete concept
criterion → one evaluative question about that concept

Defining the questions

Each criterion has five fields:

FieldPurposeExample
NameHuman-readable label used in tables and plots.Purchase intent
QuestionExact valuation prompt presented before the complete configuration.How likely would you be to purchase this configuration?
DirectionWhether larger raw values are better (maximize) or worse (minimize).Maximize intent; minimize complexity.
WeightRelative contribution to the optional composite summary.Purchase intent receives weight 2.
EvaluatorsThe stakeholder or expert panel qualified to answer this question.Consumers rate intent; a food-service expert rates cost.
zwicky criteria add "Purchase intent" \
  --question "How likely would you be to purchase this configuration?" \
  --direction maximize --weight 2 \
  --evaluators traditionalists,adventurous-diners,health-conscious-diners

zwicky criteria add "Operational cost" \
  --question "How costly would this be to prepare and serve?" \
  --direction minimize --weight 1 \
  --evaluators food-service-operations-expert

zwicky criteria add "Novelty" \
  --question "How novel and differentiated is this configuration?" \
  --direction maximize --weight 1 \
  --evaluators traditionalists,adventurous-diners,health-conscious-diners

zwicky criteria list --human

The question should name the construct being rated and provide enough context for a consistent judgment. “How good is this?” collapses several ideas into one response. Purchase intent, operational complexity, and novelty produce separate answers that can later be compared, weighted, or plotted.

What gets scored—and by whom

For each configuration, the consumer panel answers purchase intent and novelty. The expert panel separately answers operational cost. Zwicky retains the evaluator identity with every score and computes each criterion mean over only its assigned panel.

ȳck = (1/|Ak|) Σa∈Ak yackAk is the evaluator panel assigned to criterion k. For one expert, |Acost|=1.

The assessment selects criteria explicitly:

zwicky utility build \
  --sample sample-123 \
  --criteria purchase-intent,operational-cost,novelty \
  --scale 7

Omitting --criteria creates a single default “Overall utility” question. Explicit criteria are more useful when the decision contains recognizable trade-offs.

Putting maximize and minimize criteria on one orientation

Purchase intent and novelty already point upward: 7 is better than 1. Complexity points downward: 1 is better than 7. Zwicky preserves the raw answer, then reverses minimize criteria when calculating a composite. For a scale from 1 through L:

o(y)=y   for maximize
o(y)=L+1−y   for minimize

On a seven-point scale, an operational-cost rating of 2.5 becomes an oriented value of 8−2.5=5.5. A cost rating of 6 becomes an oriented value of 2. After orientation, larger numbers consistently mean better performance.

What weights do

The composite score is a weighted average of the oriented criterion means:

U(c) = [Σk wkokck)] / [Σkwk]o(y)=y for maximize and L+1−y for minimize.

With weights 2 for purchase intent, 1 for complexity, and 1 for novelty, a one-point change in purchase intent contributes twice as much to the numerator as a one-point change in either other criterion. Dividing by the total weight keeps the composite on the original 1–7 scale.

Worked comparison

ConceptIntent ↑Complexity ↓Oriented complexity ↑Novelty ↑Weighted composite
A6.22.55.53.8(2×6.2 + 5.5 + 3.8)/4 = 5.43
B5.61.86.25.9(2×5.6 + 6.2 + 5.9)/4 = 5.83
C6.55.52.56.2(2×6.5 + 2.5 + 6.2)/4 = 5.43

Concept B ranks first under these weights because its low complexity and high novelty compensate for lower purchase intent. Increasing the purchase-intent weight could change that order. Zwicky therefore retains the raw criterion means so alternative weights can be examined without rerunning the interviews.

Composite ranking versus Pareto reasoning

A composite answers: “Which configuration scores highest under these particular weights?” Pareto analysis asks a different question: “Which configurations remain efficient without specifying exchange rates between criteria?” Weights affect the composite ranking but do not affect Pareto membership. The next chapter uses the separate criterion means to construct that frontier.

12 Pareto reasoning

Configuration a dominates b when a is at least as good on every selected criterion and strictly better on at least one, respecting each direction. The Pareto frontier contains all nondominated configurations.

a ≻ b ⇔ [∀k, a is weakly better than b] ∧ [∃k, a is strictly better]
Purchase intent versus operational complexity value leaderbalancedpremiumPurchase intent → higher is betterComplexity → lower is better
Frontier membership means tradeoff efficiency, not universal optimality.
zwicky -C hot-dog utility plot utility-735de643 --type pareto \
  --x purchase-intent --y operational-cost \
  --output writeup/pareto.svg

zwicky -C hot-dog utility portfolio utility-735de643 \
  --criteria purchase-intent,operational-cost,novelty \
  --size 8

The complete hot-dog frontier

The chart is generated from all 72 feasible hot-dog configurations using zwicky utility plot. Colored, labeled points lie on the frontier; gray points are dominated for the two displayed criteria. Hover over any point to see its configuration ID, complete morphological values, and criterion scores.

Open the hot-dog Pareto plot
Consumer purchase intent versus expert-assessed operational cost for the complete feasible hot-dog box. Moving right improves intent; moving toward lower cost improves operations.
Open the purchase-intent versus novelty plot
Purchase intent versus novelty for the same 72 evaluated hot dogs. This changes only the second criterion; the configurations and evaluation records are unchanged.

Both charts come from the same routed EDSL assessment. Three consumer personas supplied 432 purchase-intent and novelty scores; one food-service expert supplied 72 operational-cost scores. The run cost $0.049655 and was ingested as utility-735de643. Pareto membership is specific to the selected criteria.

Portfolio selection begins with the highest composite-scoring frontier point, then favors morphological Hamming distance. This reduces near-duplicates.

13 Categorical feature models

The workflow changes here. The initial sample was chosen before any outcome scores existed. From this point forward, the search is adaptive: results from completed evaluations influence which configurations are evaluated next.

Random, coverage, and D-optimal sampling try to represent the feasible box without knowing which hot dogs customers will rate highly. That is the right starting point. Once the first EDSL job has been run and its results ingested, the objective changes from cover the design space to find strong outcomes efficiently while continuing to learn about uncertain parts of the space.

Choose an initialoutcome-blind sample Score it withthe EDSL job Fit a model forone outcome Select a promising,informative batch Score, ingest,and refit Repeat until the evaluation budget is spent or the decision is clear
The initial design is fixed in advance; every later batch can use the outcomes observed so far.

Turning a hot dog into model inputs

The adaptive model cannot operate directly on labels such as Pretzel and Slaw. Zwicky converts each configuration into a row of numbers: an intercept followed by one indicator for every morphological value.

x(c) = [1, 𝟙(v1∈c), …, 𝟙(vp∈c)]

For Pretzel + Veggie + Slaw + Street cart, the main-effect row is:

Feature groupOrdered valuesEncoded values
InterceptAlways present1
BunClassic, Pretzel, Gluten free0, 1, 0
SausageBeef, Chicken, Veggie0, 0, 1
ToppingOnions, Chili, Slaw0, 0, 1
Service styleStreet cart, Fast casual, Premium plated1, 0, 0
x(c) = [1 │ 0,1,0 │ 0,0,1 │ 0,0,1 │ 1,0,0]

The four-dimension hot-dog box therefore has 1 + 12 = 13 nominal main-effect features. A main-effect model learns a contribution for each selected value and adds those contributions to predict an outcome such as purchase intent. Because exactly one value is selected from each dimension, the columns contain known redundancies; Bayesian regularization stabilizes the fit, and Zwicky reports the estimable rank.

When combinations matter

A main-plus-pairwise model also includes cross-dimension interactions:

xab(c) = 𝟙(va∈c)·𝟙(vb∈c)

For the example above, Pretzel × Slaw = 1, while Classic × Slaw = 0. The hot-dog box has 54 cross-dimension pair features and 67 nominal features in total. This richer model can learn that Pretzel and Slaw work especially well together rather than assigning all of that lift to either ingredient alone. It also needs a larger and more varied scored sample. Start with main-effects; use main-plus-pairwise when interactions are important and the evaluation budget supports them.

The hot-dog handoff from initial design to adaptive search

First create an outcome-blind initial design. Here D-optimal sampling selects 14 configurations that make the 13-feature main-effects model estimable as efficiently as possible:

zwicky -C hot-dog sample create \
  --method d-optimal --features main-effects \
  --candidate-pool 72 --prior-precision 1 \
  --size 14 --seed 101 --human

sample_id: sample-f8d0d1f4
method: d-optimal
sample_size: 14
feature_count: 13
estimable_rank: 9
rows_per_feature: 1.0769
log_determinant: 16.9829

Build and run the evaluation, then ingest the returned scores. The EDSL run is the expensive step; everything after ingestion is local model fitting and selection.

zwicky -C hot-dog utility build --sample sample-f8d0d1f4 \
  --criteria purchase-intent

edsl run <jobs.ep> --output <results.ep>

zwicky -C hot-dog utility ingest utility-d43d28a2 \
  --results <results.ep>
zwicky -C hot-dog utility analyze utility-d43d28a2

Now fit a surrogate for the particular outcome the search should improve. This example uses purchase intent:

zwicky -C hot-dog model fit \
  --assessment utility-d43d28a2 \
  --criterion purchase-intent \
  --features main-effects --prior-precision 1 \
  --prediction-pool 72 --human

model_id: model-270f49de
criterion: Purchase intent (maximize)
training_configurations: 14
feature_count: 13
prediction_pool: 72
r_squared: 0.843926
rmse: 0.162921

The fitted model predicts purchase intent and uncertainty for the unscored hot dogs. A Bayesian acquisition rule then uses both quantities to choose the next 12 configurations:

zwicky -C hot-dog sample create \
  --method bayesian --surrogate model-270f49de \
  --acquisition ucb --candidate-pool 72 \
  --exploration 1.25 --diversity 0.25 \
  --size 12 --seed 202 --human

sample_id: sample-407db2ac
method: bayesian
sample_size: 12
unscored_candidates: 58
selected_predicted_mean: 5.029390
selected_mean_epistemic_std: 0.181186
values_covered: 10/12
pair_coverage: 29/53

This is the first outcome-informed sample: it is selected because of what the initial 14 consumer evaluations taught the model. Pooling the 12 follow-up configurations produced model-a144d834, trained on 26 configurations with RMSE 0.241842 and R² 0.638374.

The Sampling Designs chapter explains the D-optimal initial batch. Chapters 10 and 11 now develop the Bayesian surrogate and acquisition rule used after scores arrive.

14 Bayesian linear surrogate

Why fit a surrogate?

Suppose 80 of several thousand feasible hot dogs have received purchase-intent scores. We could simply rank those 80, but that says nothing about the unscored configurations. A surrogate is a fast statistical approximation to the expensive evaluator. It learns patterns from scored configurations, predicts scores for new ones, and attaches uncertainty to each prediction.

The surrogate does not call the digital twins again. It operates on the data already returned by the utility assessment. For one criterion at a time, Zwicky takes each configuration’s mean score as the target y and its categorical feature row as x. With main effects, the prediction is an intercept plus contributions from the selected morphological values:

predicted score = intercept + bun effect + sausage effect + topping effect + service effect

With main-plus-pairwise, the prediction can also include terms such as Pretzel × Slaw. These interaction terms let a combination perform differently from the sum of its individual value effects.

A small numerical example

Consider an illustrative fitted main-effects model:

Term active for this configurationEstimated contribution
Intercept3.4
Pretzel bun+0.5
Veggie sausage−0.2
Slaw topping+0.4
Street-cart service+0.1
Predicted purchase intent4.2

The arithmetic is 3.4 + 0.5 − 0.2 + 0.4 + 0.1 = 4.2. If Pretzel × Slaw has a +0.3 interaction in a pairwise model, the prediction becomes 4.5. Zwicky’s full categorical encoding uses regularization and a generalized inverse, so individual coefficients are best read as a jointly fitted decomposition; configuration-level predictions are the primary output.

Now suppose this concept has predicted mean 4.5 and epistemic standard deviation 0.8. Another familiar concept has mean 5.1 and epistemic standard deviation 0.3. The second currently looks stronger; the first is less certain and may be more informative to evaluate. Chapter 11 uses exactly this mean–uncertainty distinction to choose the next batch.

The Bayesian model

Let β contain all intercept, value, and optional pairwise coefficients. Before observing scores, Zwicky places a zero-centered Gaussian prior on β. The prior precision α controls shrinkage: larger α pulls effects more strongly toward zero. Observed scores are modeled as the linear prediction plus Gaussian residual noise with variance σ²:

β ~ N(0, α−1I),    y|β ~ N(Xβ, σ²I)

After observing the feature matrix X and score vector y, Bayes’ rule produces another Gaussian distribution over the coefficients:

Σ = (αI + XTX/σ²)−1
μ = ΣXTy/σ²

The posterior mean μ is the fitted coefficient vector. The posterior covariance Σ describes which effects remain uncertain and how their uncertainties move together. Zwicky estimates σ² from the training residuals, with a small floor to keep the model numerically stable.

For a new configuration with feature row x:

E[y|x]=xTμ
Varepistemic[y|x]=xTΣx
Varpredictive[y|x]=xTΣx+σ²

The predicted mean is the estimated score. Epistemic uncertainty measures uncertainty about the fitted response surface and shrinks when informative configurations are scored. Predictive uncertainty also includes residual variation σ², so it is larger. Acquisition policies use epistemic uncertainty because it identifies where another evaluation can teach the surrogate.

What model fit does

  1. Read the analyzed configuration means for the selected criterion.
  2. Reconstruct the main-effect or main-plus-pairwise feature matrix.
  3. Estimate residual noise and calculate the posterior mean and covariance.
  4. Draw a bounded implicit pool of feasible configurations without enumerating the full space.
  5. Write a predicted mean, epistemic standard deviation, and predictive standard deviation for every configuration in that pool.
  6. Save the model parameters, predictions, training IDs, and fit diagnostics as an auditable model artifact.
zwicky model fit \
  --assessment utility-initial \
  --criterion purchase-intent \
  --features main-plus-pairwise \
  --prior-precision 1 \
  --prediction-pool 10000 --human

Here --prediction-pool 10000 means “draw up to 10,000 feasible candidates and predict them,” not “materialize the entire morphological space.” A larger pool gives the subsequent acquisition step a broader search set and requires more feature-matrix memory and computation.

After a follow-up, pool analyzed assessments:

zwicky model fit \
  --assessment utility-initial utility-followup \
  --criterion purchase-intent \
  --features main-plus-pairwise

Pooling combines scores for configurations evaluated in different rounds and averages repeated scores for the same configuration. Re-fitting updates both predictions and uncertainty before the next acquisition batch.

Reading the output

OutputInterpretation
meanPosterior predicted criterion score for a candidate.
epistemic_stdUncertainty about the estimated response surface at that candidate.
predictive_stdEpistemic uncertainty plus estimated score noise.
rmseTypical in-sample residual size, in criterion-scale units.
r_squaredFraction of observed score variation represented in-sample.
rows_per_featureTraining configurations divided by nominal feature count.
noise_varianceEstimated residual variation not represented by the fitted feature terms.

15 Acquisition policies

An acquisition function prioritizes unscored configurations. Zwicky reverses the orientation for minimize criteria.

Upper confidence bound

aUCB(x)=s·μ(x)+κσe(x)s=+1 for maximize and −1 for minimize; κ is --exploration.

Thompson sampling

β̃ ~ N(μ,Σ),    aTS(x)=s·xTβ̃

A plausible response surface is drawn. Selection balances exploration and exploitation implicitly, making the seed meaningful.

Uncertainty sampling

auncertainty(x)=σe(x)

This ignores predicted utility and asks where a score would teach the model most under its assumptions.

Parallel-batch diversity

a′(x)=normalize(a(x))+λ·minz∈B[Hamming(x,z)/d]

λ is --diversity. Diversity can lower immediate predicted performance but avoids spending a parallel batch on near-identical concepts.

zwicky sample create \
  --method bayesian \
  --surrogate model-123 \
  --acquisition ucb \
  --candidate-pool 10000 \
  --exploration 1.5 \
  --diversity 0.25 \
  --size 100 --seed 456 --human
PolicyBest forDisclosure
ThompsonStochastic explore/exploit balanceThe seed chooses one plausible surface.
UCBExplicit optimism under uncertaintyReport κ and predicted-score concession.
UncertaintyLearning or diagnosing the surfaceNo attempt is made to pursue utility.

16 Worked product example: hot dogs

This example uses four three-valued dimensions, one hard incompatibility, three twin segments, and three criteria. Its evaluation figures and adaptive-search numbers come from an EDSL run completed with gpt-4.1-mini.

Evaluator panelAssigned criteria
Consumer twins: Traditionalists, Adventurous diners, Health-conscious dinersPurchase intent ↑, weight 2
Novelty ↑, weight 1
Food-service operations expertOperational cost ↓, weight 1

The box has 81 theoretical concepts. Veggie with beef-containing Chili removes nine, leaving 72 feasible concepts.

zwicky -C hot-dog utility build --all-configs \
  --criteria purchase-intent,operational-cost,novelty \
  --rationale none --batch-size 250 --human

edsl run jobs-panel-01.ep --model gpt-4.1-mini \
  --output consumer-results.ep
edsl run jobs-panel-02.ep --model gpt-4.1-mini \
  --output expert-results.ep

zwicky -C hot-dog utility ingest utility-735de643 \
  --results consumer-results.ep expert-results.ep
zwicky -C hot-dog utility analyze utility-735de643
Run factObserved value
Feasible configurations72
Consumer personas3
Food-service experts1
Agent–configuration interviews288: 216 consumer + 72 expert
Numeric criterion scores504: 432 consumer + 72 expert
Modelgpt-4.1-mini
Recorded inference cost$0.049655

Download the consumer Results and expert Results packages. Zwicky ingests both into one assessment. The adaptive chapters replay purchase-intent search using only consumer-panel scores.

The purchase-intent versus operational-cost and purchase-intent versus novelty plots each contain all 72 hot dogs. Each axis is supported by its assigned evaluator panel.

17 Hot-dog results: twins and fitted models

The aggregate ranking is only one view of the 504 ratings. The assessment can also show how the consumer perspectives differ, how the expert evaluates cost, which morphological values drive preference, and how well the adaptive surrogate generalizes.

How each twin used the criteria

Open the twin-ratings heatmap
Consumer twins rate preference criteria; the food-service expert rates operational cost once per configuration. Means use the raw 1–7 scales.

The heatmap reveals response-level differences before any criterion weights are applied. Traditionalists averaged 3.33 on purchase intent, compared with 5.39 for adventurous diners and 4.58 for health-conscious diners. The expert’s mean operational-cost rating was 5.13. These are different constructs from different evaluator roles, joined at the configuration level rather than averaged as interchangeable opinions.

Which values drive purchase intent?

Open the value-profile plot
Every dot averages purchase-intent ratings for all feasible configurations containing that value. Hover over a dot for the exact twin and mean.

This is a descriptive marginal view: it answers questions such as whether the health-conscious twin scores Veggie above Beef, or whether Premium plated changes the adventurous twin’s ratings. Because the feasible box is not a perfectly independent factorial design after CCA pruning, these dots summarize observed configurations rather than claiming isolated causal effects. The fitted model below estimates the effects jointly.

Did the adaptive model learn the full response surface?

zwicky -C hot-dog model fit \
  --assessment utility-d43d28a2 \
  --criterion purchase-intent --features main-effects \
  --prediction-pool 72 --human

zwicky -C hot-dog model fit \
  --assessment utility-d43d28a2 utility-f72f4e33 \
  --criterion purchase-intent --features main-effects \
  --prediction-pool 72 --human
Open the fitted-model diagnostic
The dashed line is perfect prediction. Green configurations were used in each fit; gray configurations were hidden during that stage of the adaptive replay. Hover over a point for its observed mean, predicted mean, and epistemic standard deviation.

The 14-configuration model achieved training RMSE 0.163; its RMSE across all 72 configurations was 0.411 and its held-out RMSE was 0.451. After adding the 12 UCB-selected configurations, training RMSE was 0.242, all-configuration RMSE was 0.391, and held-out RMSE was 0.455. The adaptive batch improved error across the complete known box slightly while leaving error on the changing held-out set essentially flat.

This is the trade-off surfaced by adaptive search: the batch can concentrate evaluation on likely winners, reduce uncertainty in decision-relevant regions, or improve global model fidelity, but one acquisition rule does not maximize all three at once. The held-out plot makes that choice visible alongside the selected batch’s predicted mean, uncertainty, coverage, and exploitation cost.

18 Reporting, judgment, and audit

Zwicky does not write the final narrative. It converts the assessment into focused evidence artifacts so a report-writing agent does not have to reverse-engineer raw score rows. The hot-dog assessment below shows the complete handoff.

1. Preview: document what was actually run

utility preview reconstructs the study design: evaluator panels, assigned criteria, exact rendered questions, agent traits and instructions, scale endpoints, scenario text, expected counts, and EDSL commands. This is the source for the report’s methodology section.

zwicky -C hot-dog utility preview utility-735de643 \
  --examples 2 --human

agents: 4
configurations: 72
expected_interviews: 288
expected_numeric_scores: 504
evaluator_panels:
  consumer panel: 3 agents → purchase_intent, novelty
  expert panel:   1 agent  → operational_cost
examples:
  traditionalists → purchase_intent, novelty
  food-service-operations-expert → operational_cost

The two examples confirm that the consumer and expert see the same Classic + Beef + Onions + Street cart configuration but receive different questions.

2. Compare: turn configuration IDs into concept cards

utility compare joins each finalist to readable dimension values, criterion means, composite score, Pareto status, evaluator-specific scores, rationales, and the dimensions that differ. The report agent can use this directly for a side-by-side finalist table.

zwicky -C hot-dog utility compare utility-735de643 \
  --configs 1a775c381223 9aef2db02e8e 3995881316db --human

comparison_id: comparison-7c2f77cd
differing_dimensions: Sausage, Topping, Service style
ConfigurationConceptIntent ↑Cost ↓Novelty ↑Composite
1a775c381223Pretzel · Veggie · Onions · Fast casual5.0045.334.83
9aef2db02e8ePretzel · Veggie · Slaw · Street cart5.0056.334.83
3995881316dbPretzel · Chicken · Slaw · Fast casual4.6745.674.75

All three are Pareto-efficient. The first two tie on the weighted composite for different reasons: the fast-casual Onions concept has lower expert-rated cost, while the street-cart Slaw concept has higher consumer-rated novelty.

3. Disagreement: identify segment-dependent concepts

utility disagreement calculates score dispersion and the range between evaluator-segment means for every configuration and criterion. It surfaces concepts whose aggregate mean conceals a sharply divided audience.

zwicky -C hot-dog utility disagreement utility-735de643 \
  --limit 10 --human

mean stakeholder range:
  purchase_intent: 2.5556
  novelty:         0.8472
  operational_cost: 0.0000

most divisive:
  Gluten free · Veggie · Onions · Premium plated
  purchase intent mean: 5.0
  Traditionalists: 2 · Adventurous: 6 · Health-conscious: 7

The zero cost range has a precise meaning: operational cost has one assigned expert, so there is no between-evaluator disagreement to calculate. Purchase intent is where the segment split occurs.

4. Sensitivity: vary the importance of the criteria

The baseline composite uses the declared 2:1:1 weights. utility sensitivity draws alternative nonnegative weight vectors that sum to one, reranks all configurations, and reports how often each concept wins plus its best, worst, and average rank.

zwicky -C hot-dog utility sensitivity utility-735de643 \
  --criteria purchase-intent,operational-cost,novelty \
  --draws 1000 --seed 123 --human

baseline weights: intent 0.50 · cost 0.25 · novelty 0.25
Pretzel · Veggie · Slaw · Street cart:
  baseline rank 2 · win share 40.0% · rank range 1–19
Pretzel · Veggie · Onions · Fast casual:
  baseline rank 1 · win share 5.0% · rank range 1–16
Pretzel · Chicken · Slaw · Fast casual:
  baseline rank 3 · win share 10.7% · rank range 1–20

The baseline leader is not the most frequent winner under alternative priorities. That gives the report a concrete conclusion: the recommendation depends on whether the decision emphasizes balanced baseline weights or the broader range of plausible priorities.

5. Shortlist: preserve efficient, distinct alternatives

utility shortlist starts with the highest-composite point on the selected-criteria Pareto frontier, then greedily adds frontier points that differ morphologically from those already chosen. Each row explains its inclusion, strongest criterion, principal trade-off, and distance from earlier selections.

zwicky -C hot-dog utility shortlist utility-735de643 \
  --criteria purchase-intent,operational-cost,novelty \
  --size 6 --human

shortlist_id: shortlist-f8aad270
frontier_count: 8
selected: 6
1. Pretzel · Veggie · Slaw · Street cart
   highest composite frontier point; novelty 6.33; cost 5
2. Gluten free · Chicken · Slaw · Fast casual
   three dimensions from #1; intent 5.33
3. Classic · Veggie · Onions · Fast casual
   three dimensions from earlier choices; cost 3

This is a decision set, not six restatements of the same winner. The report-writing agent can name the concepts, explain their distinct roles, and recommend which should advance to the next validation stage.

From artifacts to the report

The commands write JSON under .zwicky/utility/assessments/utility-735de643/decision/. The IDs above—comparison-7c2f77cd, sensitivity-ebc2214a, and shortlist-f8aad270—make every reported table traceable to its source artifact.

zwicky -C hot-dog guide
zwicky -C hot-dog report guide
zwicky -C hot-dog report template

# The separate report-writing agent produces:
writeup/report.md

guide reports which decision artifacts exist and which are still missing. report guide describes the available evidence and narrative requirements. report template provides the report structure. The writing agent then turns the artifacts into context, findings, trade-offs, recommendations, and next steps rather than copying tool output verbatim.