zcash / halo2

The Halo2 zero-knowledge proving system
https://zcash.github.io/halo2/
Other
722 stars 492 forks source link

Enable floor planners to configure columns #195

Open str4d opened 3 years ago

str4d commented 3 years ago

Currently, every time ConstraintSystem::advice_column etc is called, it allocates a fresh column. Chips require two kinds of columns:

If we only have a single chip in the circuit, then it doesn't matter where the columns are allocated; the Layouter is sufficient to lay out a circuit efficiently.

If we have two chips (cores?) in the same circuit that need to communicate, we allocate the bus columns at the circuit level and then explicitly pass them into each chip. However, the internal columns will be allocated independently, resulting in poor laying out of regions.

Instead, we should add namespacing to ConstraintSystem, to enable it to reason about what kinds of regions will use what kinds of columns. This could then be used by a floor planner to decide how to allocate concrete columns, in the same way that the Layouter decides how to assign concrete rows.

daira commented 3 years ago

As I'd imagined it, there would be only one place in the code where you allocate columns for a given circuit. In that place, you also instantiate the cores and pass whatever columns are needed into each core. Cores never allocate columns themselves (as you say, they can't do so efficiently).

The reason to do it this way is that sharing columns between cores is necessarily a global optimization. In general, you don't have enough information to do it efficiently unless you know all the cores you're using.

Now, you may argue that this means a circuit has to know too much about implementation details of the cores it depends on. In practice it's fine, though. It doesn't matter if circuit configuration code is not very reusable, or if it has to change when the column usage of the cores it depends on changes, because it's a relatively small amount of simple code. It's just no big deal, as least for now and for this layer of the API.

In the glorious future where we have a compiler from a high-level language, it will be able to infer how to share columns. But it's a hard problem and we have no need to solve it yet.

str4d commented 2 years ago

I've generalised this issue to be about enabling floor planners to perform horizontal optimizations - both deciding how many columns (of each kind) to allocate, and how to distribute them amongst the configured chips. Existing floor planners would be updated in a way that just requires circuits to retain the existing manually-configured logic.

str4d commented 2 years ago

In a pairing between @daira, @therealyingtong and myself, we had some discussion about this.

str4d commented 2 years ago

Had another short discussion about this today with @daira and @therealyingtong. In order for efficient optimisers to be written, we need to give bounds on the rows and columns. This is effectively what we already do for the layouter: users specify their desired k value, and then the layouter optimises vertically to reduce the actual number of rows it consumes. But the circuit won't fully take advantage of that improvement unless the user lowers their k value. The same could be done with columns: the user configures the "maximum" (actual) number of columns to use, and the optimiser minimises within that (or perhaps uses all those columns in exchange to reducing rows further, depending on its settings).

Note that we only need for advice columns and non-selector fixed columns. Selector columns would not need a bound, because they serve a different role than a true fixed column. Users only ever enable selectors, they never set arbitrary values. Ergo the optimiser can just compress selectors as much as it wants.