Skip to content

About

Bend 2 port of U-NSGA-III. Published 0.1.0 content-hash hub package (not NuGet). C# Unsga3 is the NuGet/GitHub Packages reference. A/B via ZDT/DTLZ + IGD.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

61 Commits

Folders and files

Repository files navigation

unsga3-bend

Greenfield Bend 2 port of U-NSGA-III (Seada & Deb, 2016).

This repository is standalone public OSS. It is not a NuGet package, not PackageId Unsga3, not a drop-in replacement for C# consumers, and not a dependency of any private product. Consumers that already use the C# library keep using that library; this repo does not know about those applications.

https://github.com/AppSprout-dev/unsga3-bend

Relation to C# Unsga3

The reference implementation is the existing C# library:

unsga3-bend is a from-scratch Bend 2 port of the algorithm core, not a binding and not a republish of that package. The two stacks sit beside each other: C# remains the .NET package; this tree is the Bend hub package. The shared validation plan is the same public protocol the C# docs use: ZDT / DTLZ problems and IGD against a pymoo UNSGA3 oracle (C# docs/EQUIVALENCE.md).

Hub package (0.2.2)

0.2.2 is the current Bend content-hash hub package. bend src/lib.bend --publish ran again for this tree (Bend 2.0.34) and the content hash changed. Artifacts do not go to nuget.org or GitHub Packages.

0.1.0 was the first hub publish (0xcd07e24a626a62e74603d48f436cd679). GitHub 0.1.1 was a docs/ab confidence bump (multi-seed IGD tables + Layer-1 fixture check) and did not re-publish. GitHub 0.1.2 (0x527a2a4fa91b05a0250d7be0e11d232a) includes the RankNicheDistance fix. 0.2.0 (0xa2f9d6ef8c474468bf1de15ebe70c512) adds the unconstrained problem catalog, Deb constraint-domination, the offspring duplicate contract, and the odd-N SBX fix. 0.2.1 (0x2bc7fb472c80bd6a0e04725c117edb2a) adds the DTLZ3 axis clamp, OSY / TNK / C1-DTLZ1, and the CV-fill overflow fix. 0.2.2 (0xd1de66b5d9157913a654c39186289f3d) keeps the speed-dig niche bags and associate residual. A/B stays PymooCompatible. Git tags v0.2.0 and v0.2.1 and their GitHub Releases exist. Tag v0.2.2 follows once this commit is main's tip.

How consumers import

Bend fetches a published package by content hash (bend guide § Modules). Consumer-facing import (package alias Unsga3):

import 0xd1de66b5d9157913a654c39186289f3d/lib.bend as Unsga3

bend src/lib.bend --publish printed this exact line (alias Lib):

import 0xd1de66b5d9157913a654c39186289f3d/lib.bend as Lib

The hub entry path is /lib.bend (what bend printed), not /src/lib.bend. Content hash: 0xd1de66b5d9157913a654c39186289f3d.

The named package unified-nsga-iii@0.1.2.0 still points at the 0.1.2 hash. unified-nsga-iii@0.2.0.0 still resolves to 0xa2f9d6ef8c474468bf1de15ebe70c512. Once this commit is main's tip, bend link unified-nsga-iii@0.2.2.0 0xd1de66b5d9157913a654c39186289f3d.

Develop against src/ in this checkout with a local path:

import ./src/lib.bend as Unsga3

src/lib.bend is the module-graph facade (core + variation + problems + Run). See CHANGELOG.md.

What is in this tree

Shipped in the 0.2.2 hub package (algorithm + A/B helpers):

  • Core — non-dominated sort, NSGA-III normalization, Das–Dennis directions, niching / association, survival
  • Variation + Run — decision variables, SBX (η=30, p=1.0), polynomial mutation (η=20, p=1/n), ZDT1 / ZDT2 / DTLZ2 (3-obj), PymooCompatible tournament, Unsga3Algorithm.Run
  • Catalog — ZDT3 / ZDT4 / ZDT6, DTLZ1 / DTLZ3 / DTLZ4 / DTLZ7, Sphere / Ackley / Rosenbrock. In this hub hash, including the DTLZ3 axis clamp. Dumpable. Measured IGD: docs/ORACLE-CATALOG.md
  • Constrained demos — OSY, TNK, C1-DTLZ1 in this hub hash. Feasible-only survival and hyperplane. Smoke binary: bend src/constrained_smoke.bend -o. Cells: docs/CONSTRAINED-SURFACES.md
  • Constraints + offspring — Deb constraint-domination (cv on Individual), CV-first tournaments, survivor-set duplicate keys, odd-N SBX (parent N-1 with parent 0). A/B stays PymooCompatible
  • Parallel maps — independent per-individual work uses Bend a b = f(lo) f(hi) mid-splits. Tournament, SBX, mutation, and last-front niching stay sequential so a fixed seed consumes RNG in the same order
  • Native dumps — bend src/….bend -o … then run the binary. ab/dump_bend_run.py --native prefers that path and falls back to bend file.bend if the build fails
  • Proofs — bend PROOF.bend is 0 ?TODO. Public “proves” / “resolved” verbs follow docs/PROOF-SURFACE.md.

Measured native phase tables (not IGD): docs/PERF_NOTES.md. Protocol: docs/EQUIVALENCE.md.

Module C# surface it mirrors
Individual objectives + variables + evaluated + rank/niche bookkeeping
NonDominatedSort fast non-dominated sort + Pareto compare
Normalization NSGA-III adaptive hyperplane (persistent across Run)
ReferenceDirections Das–Dennis directions / count
Survival niching association + environmental selection
problems Zdt1 / Zdt2 / Zdt3 / Zdt4 / Zdt6, Dtlz1 / Dtlz2 / Dtlz3 / Dtlz4 / Dtlz7, Sphere / Ackley / Rosenbrock, Osy / Tnk / C1Dtlz1
tournament TournamentSelection / TournamentMode
algorithm Unsga3Algorithm.Run

How A/B works

Two layers; do not invent IGD numbers in this repo.

  1. v0 core A/B — feed the same objective population to C# and Bend sort / normalize / associate / select. Compare ranks, associations, and the selected index set.
  2. Algorithm A/B — dump ND fronts from Bend Run (and optionally C# OracleCompare when UNSGA3_CS_ROOT is set) on shared ZDT/DTLZ settings; IGD vs pymoo when installed.

Protocol (same as C# docs/EQUIVALENCE.md / tools/OracleCompare; dump defaults in ab/protocol.py):

Label Problem Partitions Pop Gens Seed Tournament
oracle ZDT1 ZDT1 n=30 12 52 100 1 PymooCompatible
oracle ZDT2 ZDT2 n=30 12 52 250 1 PymooCompatible
oracle DTLZ2 DTLZ2 M=3 k=10 12 92 150 1 PymooCompatible
smoke ZDT1 (checked-in) ZDT1 n=30 4 8 3 1 PymooCompatible

Operators: SBX η=30, PM η=20, p_c=1.0, p_m=1/n. Smoke is labeled smoke and is not an oracle claim. ZDT2 quality protocol is gens=250; gens=100 is an early-stress snapshot (PR #16: Bend 10/15 and C# 8/15 collapse), not the A/B default — see docs/ZDT2_COLLAPSE.md and ab/protocol.py. RankNicheDistance is an optional dump flag (--tournament rank_niche), not the new default.

Intentional deltas vs C#: Sort uses Deb constraint-domination (equal infeasible CV is mutual non-domination; published C# CompareConstraintDominated still Pareto-compares that tie). Oracle ZDT1 / ZDT2 / DTLZ2 stay unconstrained (CV 0); OSY / TNK / C1-DTLZ1 exercise the Deb / CV path. Bend RNG is a portable LCG (not System.Random), so fronts will not match bit-for-bit. Run survival niching threads rng for min-count niche ties (C# Select(..., rng)); last-front extras are random among near-best on the ray, not uniform inNiche[rng.Next] (that LCG path collapsed oracle ZDT2). v0 select stays deterministic. Duplicate keys round decision variables to 12 decimal places (round(x*1e12)/1e12), which is not C# ToString("G12") significant digits (small variables diverge; see src/g12_key.bend). Unequal-length objectives are mutual non-domination (C# ComparePareto throws; see src/nds_unequal.bend). C# ctor default tournament is RankNicheDistance; Bend A/B / smoke uses PymooCompatible. GitHub 0.1.2 orders that optional key as rank, then niche count, then perpendicular distance, then a coin. DTLZ2 IGD uses a Das–Dennis-density PF (see ab/README.md); pymoo’s default ~136-pt PF is a different yardstick.

Install Bend and check this tree

Bend is not assumed to be on PATH. Install from the official script:

curl -fsSL https://bend-lang.com/install.sh | sh
export PATH="$HOME/.bend/bin:$PATH"
export BEND_NO_TELEMETRY=1
bend guide

Smoke (not the quality protocol — ZDT1 pop=8, gens=3):

bend src/lib.bend       # module graph: All terms check (Bend 2.0.10+)
bend src/ab_select.bend # v0 selection smoke (prints CSV front)
bend src/op_smoke.bend  # SBX + poly mutation on a 2-var box, seed 42
bend src/run_smoke.bend # short fixed-seed ZDT1 Run; prints ND front CSV
bend PROOF.bend         # gate: all LAWS.bend claims closed (0 ?TODO)
mkdir -p ab/out
bend src/run_smoke.bend -o ab/out/run_smoke   # clang 14+
./ab/out/run_smoke --threads 8
python3 ab/dump_bend_front.py
python3 ab/dump_bend_run.py --native          # same smoke; fallback to `bend file.bend`

Quality A/B (optional; pass the table knobs — see docs/EQUIVALENCE.md):

python3 ab/dump_bend_run.py --native --problem zdt1 --partitions 12 --pop 52 --gens 100 --seed 1
python3 ab/dump_bend_run.py --native --problem zdt2 --partitions 12 --pop 52 --seed 1
# omitted --gens on zdt2 is 250 (ab/protocol.py). --gens 100 is early-stress only.
python3 ab/dump_bend_run.py --native --problem dtlz2 --partitions 12 --pop 92 --gens 150 --seed 1
python3 ab/dump_csharp_front.py   # skip if UNSGA3_CS_ROOT unset
python3 ab/dump_csharp_run.py     # skip if UNSGA3_CS_ROOT unset
python3 ab/igd_vs_pymoo.py --front ab/out/bend_run_F.csv --problem zdt1 --pf-points 500

dump_bend_run.py writes the # header plus objective rows (Bend's All terms check banner is stripped so interpreter and native dumps match). --bin PATH runs an already-built binary. UNSGA3_BEND_NATIVE=1 is the same as --native. --interpreter forces bend file.bend. Do not invent timings or IGD.

Language: bend-lang.com · github.com/bendlang/bend. How to contribute: CONTRIBUTING.md.

Modules are .bend files: import Base, import ./x.bend as M. Laws live in LAWS.bend (human-owned). Proofs live in PROOF.bend. bend PROOF.bend is the gate.

Layout

unsga3-bend/
├── AGENTS.md                 # Bend agent rules + product locks
├── CHANGELOG.md              # 0.2.2 hub re-publish (speed-dig niche + associate)
├── CONTRIBUTING.md           # install / smoke / proofs / do-nots
├── LAWS.bend                 # core + operator + Run/ZDT claims (human-owned)
├── PROOF.bend                # imports LAWS; closed proofs
├── challenges/               # statement fixtures; they do not replace the wall
├── src/                      # core + variation + problems + Run + smokes
├── ab/                       # core + algorithm dump / optional IGD / optional C#
├── ab/protocol.py            # A/B defaults (ZDT2 gens=250)
├── docs/EQUIVALENCE.md       # public protocol (this tree)
├── docs/PROOF-SURFACE.md     # proof_surface enum + public verb gate
├── docs/ORACLE-MULTISEED.md  # 15-seed IGD + Layer-1 fixture check
├── docs/ROADMAP.md
├── docs/PERF_NOTES.md        # measured warm-native phases (not IGD)
├── docs/ZDT2_COLLAPSE.md     # ZDT2 gens=100 early-stress vs gens=250 quality
└── LICENSE                   # MIT
Doc Role
CONTRIBUTING.md how to check the tree
docs/EQUIVALENCE.md quality protocol + C# pointer
docs/PROOF-SURFACE.md proof_surface enum and the verb gate
challenges/README.md Laws.niche_count_sum statement fixture
docs/ORACLE-MULTISEED.md 15-seed IGD (Bend / C# / pymoo NSGA-III) + fixture bit-check
docs/ZDT2_COLLAPSE.md why ZDT2 gens=100 is early-stress
docs/PERF_NOTES.md warm-native phase tables
docs/ROADMAP.md shipped vs open
ab/README.md dump / IGD scripts

License

MIT — see LICENSE.

Not affiliated with pymoo. A/B scripts compare against pymoo as an external tool when it is installed; this repo does not vendor pymoo.

About

Bend 2 port of U-NSGA-III. Published 0.1.0 content-hash hub package (not NuGet). C# Unsga3 is the NuGet/GitHub Packages reference. A/B via ZDT/DTLZ + IGD.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages