Goal Attainment — Control Systems/Optimization
Control_Systems/Optimization/Goal_Attainment · 1 input / 4 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text
Description#
The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.
Goal Attainment
Control Systems / Optimization
Brings m polynomials as close to their goals as the weights allow, their
coefficients arriving on a port – MATLAB's fgoalattain,
solved again on every sample:
minimize γ over x and γ such that Fi(x) − wi·γ ≤ goali, i = 1 … m
with Fi(x) = Σt ci,t ·
x1e(t,1) · … ·
xne(t,n). γ is the attainment factor: negative
when every goal is beaten, positive when they cannot all be met, and the weights
say how the shortfall is shared – objective i gives up wi·γ
against its goal. A weight of 0 makes that goal a hard constraint,
Fi(x) ≤ goali, which is fgoalattain's own
convention.
The exponents e are configuration – the problem's shape, which
fixes the loop bounds every export unrolls. The m objectives share that ONE term
dictionary, and their coefficients c are the signal: one column per
objective, stacked into a single port. The goals and weights are
configuration. The search is fgoalattain's own sequential quadratic
programming method – a BFGS Hessian approximation, an active-set QP with its
own feasibility phase, and a merit line search – with exact gradients,
because a polynomial's gradient is another polynomial. It is the solver
Minimax runs, at every goal 0 and every weight 1.
The factory setting is fgoalattain's documented example:
F₁ = 2 + (x−3)² and F₂ = 5 + x²/4 over the terms
[2; 1; 0] (x², x, 1) with coefficients [1; −6; 11;
0.25; 0; 5], goals [3; 6] and weights 1/3 and 1/6 – entered as
[0.3333333333333333; 0.16666666666666666], because a setting is a number
list and not an expression – from x = 1.
Its answer is x = 2, where both goals are met exactly and γ = 0.
Ports
- c – the coefficients, a column [m·T,1]: rows 1..T are objective 1's, one per ROW of Term Exponents in the same order, rows T+1..2T objective 2's, and so on. A row vector is refused.
- x – the solution, [n,1] (n = the columns of Term Exponents).
- F(x) – every objective at x, [m,1].
- attainfactor – γ, a scalar [1,1]
(
fgoalattain'sattainfactor). - exitflag – a scalar [1,1],
fgoalattain's own: 4 the search direction became smaller than twice Step Tolerance; 5 the predicted change in γ became smaller than Function Tolerance (both with the constraints met); 0 a limit below stopped the search; −2 no point was found where the constraints hold – which a hard goal (weight 0) that cannot be met produces.fgoalattainhas no flag 1: its first-order test is switched off for this problem.
Parameters
- Options – empty (default), or the path of a Solver Options block (
Home/Solver Options), MATLAB’s options argument: for the run, every option it sets replaces this block’s parameter of the same name; one it leaves atdefault, or one this block does not have, changes nothing. - Term Exponents – a [T,n] matrix of whole numbers from 0 to 4: row t, column i is the power of xi in term t. T is 1 to 8, n is 1 to 4, and no term may total more than degree 4. The caps are the export's, not the search's – see Code export.
- Goal – the goals, one per objective: its length is m, from 1 to 6.
- Weight – the weights, the same length as Goal. Positive weights share an over- or under-attainment in proportion; MATLAB suggests |Goal| to make the shortfall relative (1 where a goal is 0), and a negative weight asks an objective to exceed its goal. 0 makes the goal a hard constraint.
- Start Point – x0, n entries. The search is LOCAL, so on a non-convex problem this chooses which solution is found.
- Step Tolerance – StepTolerance, positive; default 1e-6. The search stops with flag 4 once the largest entry of the QP step is below twice this.
- Function Tolerance – FunctionTolerance, positive; default 1e-6. The search stops with flag 5 once the step's predicted change in γ is below this.
- Constraint Tolerance – ConstraintTolerance, positive; default 1e-6: how far a goal constraint may be exceeded and still count as met.
- Maximum Iterations – MaxIterations, 1 to 2000, default 400, MATLAB's own.
- Maximum Function Evaluations –
MaxFunctionEvaluations, 0 to 2000. 0 (the default) means MATLAB's
own, 100·(n+1) – the +1 is γ, which
fgoalattaincounts as a variable. - Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. Each prints the same description of the iteration that the simulation itself runs, so every target does the same arithmetic in the same order as the simulation. The goals and weights are printed into the code as literals.
The exponent pattern is unrolled once: each term's monomial and its n partial derivatives, shared by every objective. The iteration is emitted with fixed trip counts and flags that stop the arithmetic once the answer is found, because none of the ten has an unbounded loop a hardware target could also carry.
⚠ The three HDL targets run the search in simulation-only real arithmetic, quantizing only at the port boundaries: a QP divides and compares across many orders of magnitude, which a Q16.16 datapath does not carry.
Simulink bridge
None (Support::None). The Optimization Toolbox ships no
Simulink library at all and fgoalattain is a MATLAB function, so there
is no block to map onto; the bridge reports this block rather than dropping it
silently, and it has no parity testbench. Code export verification still covers it
across all ten languages.
Notes
- Stateless: the search restarts from Start Point on every sample, so the answer depends only on the coefficients present at that step.
- ⚠ LOCAL. The method finds a point no small step improves; on a non-convex problem that can depend on Start Point.
- ⚠ If γ is unbounded below – every weighted objective can be driven down together – there is no answer, and the point reported is wherever the evaluation limit stopped the search (flag 0) or the line search gave up.
- eps has no spelling in nine of the ten targets, so MATLAB's
epsand the constants built from it are the exact binary values here.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Optimization/Goal_Attainment |
| family | Control_Systems/Optimization |
| solver environment class | ICoreBlock_0_Control_Systems_1_Optimization_2_Goal_Attainment |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Optimization/Goal_Attainment/ICoreBlock_0_Control_Systems_1_Optimization_2_Goal_Attainment.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Optimization/Goal_Attainment/ICoreBlock_0_Control_Systems_1_Optimization_2_Goal_Attainment.h |
| default size on canvas | 170 × 110 px |
| ports at insert | 1 in, 4 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | c |
| 2 | out | ICoreDouble | x |
| 3 | out | ICoreDouble | F(x) |
| 4 | out | ICoreDouble | attainfactor |
| 5 | out | ICoreDouble | exitflag |
Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.
Configuration variables#
| Config variable | Default | Simulink parameter |
|---|---|---|
Term Exponents | [2; 1; 0] | — |
Goal | [3; 6] | — |
Weight | [0.3333333333333333; 0.16666666666666666] | — |
Start Point | 1 | — |
Step Tolerance | 1e-6 | — |
Function Tolerance | 1e-6 | — |
Constraint Tolerance | 1e-6 | — |
Maximum Iterations | 400 | — |
Maximum Function Evaluations | 0 | — |
Options | — | — |
Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
Caveat (shown to the user): the Optimization Toolbox ships no Simulink library at all, so there is no block to map onto and no library path a diagram could name; fgoalattain is a MATLAB function. The block is reported rather than dropped when a model crosses
Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:
B0no sample under docs/generated/samples/ — nothing to cross-check (P8.1)
The verdict above is
tools/docs/check_block_descriptions.py(P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.
File banner (developer view)#
The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).
Goal Attainment -- fgoalattain over m polynomials whose coefficients are a wire F_i(x) = sum over terms of c(i,t) * x1^e(t,1) * ... * xn^e(t,n), i = 1 .. m minimize gamma such that F_i(x) - w_i * gamma <= goal_i [x, fval, attainfactor, exitflag] = fgoalattain(F, x0, goal, weight)
THE OBJECTIVE SEAM IS THE FAMILY'S, and Minimax's: the exponent pattern is configuration and the m objectives share it, their coefficient columns stacked into one port. The GOAL and the WEIGHT are configuration too -- they are the design brief, not the measurement.
THE SOLVER IS fgoalattain's OWN, TRANSCRIBED, and it is ICoreGoalAttainmentSupport, shared with Minimax. goalcon.m turns each objective into (F_i(x) - goal_i)/w_i - gamma <= 0, goalfun.m makes gamma the objective, and nlconst.m's SQP with qpsub.m as its QP minimizes it. A ZERO weight is goalcon's hard constraint, F_i(x) <= goal_i with no gamma in it, and is carried the same way.
⚠ MEASURED AGAINST R2026a, with the analytic gradient supplied to fgoalattain as this block computes it (SpecifyObjectiveGradient = true), over 1300 random problems -- n = 1..4 variables, m = 1..4 objectives, up to 8 terms of degree <= 4, goals in [-1, 2], weights of 1, |goal|, a random positive value or (one row in ten) a hard zero -- the PROGRAM THIS BLOCK RUNS, compiled standalone and fed the same corpus:
exit flag identical 1300 / 1300 iteration count identical 1297 / 1300 evaluation count identical 1299 / 1300 converged answers (flag 4/5, 1254 of them): x within 1e-12 relative on 1246, bit-identical on 139
The widest converged difference -- 1.0e-2 relative in x, 4.5e-5 in the attainment factor, on one problem -- is a badly scaled one: a hard goal (weight 0) held exactly while gamma climbs to 1.0e4 at x near -79. Both solvers take the same 49 iterations and 233 evaluations there and stop on the same step test; the last-bit differences have simply had far to grow.
At the factory setting, fgoalattain's own documented example (F = [2+(x-3)^2; 5+x^2/4], goal [3; 6], weight [1/3; 1/6], from 1), this block answers x = 2 with an attainment factor of -7.68181578697719e-14 in 5 iterations and 9 evaluations, flag 4 -- fgoalattain's figures to every digit MATLAB prints.
The three HDL targets carry the iteration in
real: SIMULATION-ONLY, quantized at the ports.
Sample results#
No sample run is committed for this block. Samples come from the headless harness (DOCS_PLAN.md P8.1) into docs/generated/samples/; until one exists this block's behaviour is witnessed by the parity and export-verification suites, not by a plot here.