Skip to content

a diagonal read has no operator: at refuses an operand that already carries the key, so flow_cap[t, link_from(t)] needs a mask over the pair #771

Description

@FBumann

Prompt: "Let’s add one parent issue for caliope and file focused issues for individual topics or link existing ones."

Note

The following content was generated by AI.

What can be improved?

Calliope reads a variable over [nodes, techs] at the node a per-technology lookup names. No operator on main reads this. This re-files #621 with the model its closing comment asked for. The proposal: at joins on a key column the operand already carries.

Case, what fails, proposal, triage

Case. Calliope v0.7.0 declares link_from and link_to as per-technology lookups onto nodes. flow_cap is over [nodes, techs, carriers], because a transmission link has a capacity at each end. symmetric_transmission states that the two ends have the same capacity. It reads flow_cap at nodes = link_from(t), which is a diagonal. Calliope writes this as map_dim(nodes, link_from). The same shape occurs in the flow_out/flow_in masks and in the share examples (a slice by a per-technology carrier).

The port in #770 declares the lookups as bare relations over the pair, link_from: {key: [techs, nodes]}, masks flow_cap with a case, and sums over nodes:

symmetric_transmission:
  dims: [techs, carriers]
  expression: sum(flow_cap_from, over=nodes) == sum(flow_cap_to, over=nodes)

What fails on main (5fce82b).

base = {'dimensions': {'techs': {}, 'nodes': {}},
        'relations': {'link_from': {'key': 'techs', 'values': 'nodes'},
                      'link_to': {'key': 'techs', 'values': 'nodes'}},
        'variables': {'flow_cap': {'dims': ['techs', 'nodes'], 'bounds': {'lower': 0}}}}
# constraint over [techs]:
at(flow_cap, by=link_from, over=nodes, into=techs) == at(flow_cap, by=link_to, over=nodes, into=techs)
# at(by=link_from) lands on ['techs'], which the expression already carries.

sum(by=) refuses the same read and points back to at. That error loop is a separate bug, filed on its own.

Why #621's closing does not hold here. It said that sum(by=) and at(by=) cover the need, and that a declaration over [node, commodity] masked to the diagonal is "what relations exist to avoid". flow_cap over [nodes, techs] is not avoidable here, because a link has a capacity at both ends. The row in limits.md, "a where comparing a relation column against the dimension it maps into", tells you to use sum(by=) or at(by=). Neither loads for this case.

Proposal. at(x, by=r, over=a, into=b) where x already carries b: join on b, and read x[b, r(b)]. This is the rule sum(by=) already applies to the other key columns ("the other key columns are joined on"). The result drops a and keeps b once. It prints as $\mathrm{flow_cap}_{t,,\mathrm{link_from}(t)}$. No new operator, and no where form.

Triage against limits.md: a relaxation of an existing primitive, not a new one. The limits.md row keeps its refusal of the where comparison. Its "Instead" column then holds for this case.

Open.

  • Is the join implicit, or does it need a keyword so that "lands on a carried dim" still catches a mistake?
  • The same question applies to at over a predicate in a where:.

Version

main at 5fce82b. Found by the Calliope port, #770.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: operatorsWhat an operator may reduce, walk, read or refusedesign: openIn scope; the spelling is undecided

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions