Docs


Problem Builder

Define a custom optimization problem step by step, no code required. Supports multiple objectives.

Last updated October 17, 2026

Go to the live page Open the Problem Builder

The Problem Builder is a guided wizard that lets you define a custom optimization problem from scratch. You pick the variables, write a formula or choose a built-in fitness function, optionally add more objectives, and the platform runs the problem for you. Saved problems show up under My problems so you can re-run or tweak them later.

Builder runs use the same queue, account limits, and result workflow as other submissions. Results from user-written Builder code are also read inside the secure execution environment.

Why Use the Problem Builder?

Quick submissions cover the handful of pre-built problem shapes the platform ships with. The New Submission form gives you a blank canvas of Python code. The Problem Builder sits between them and earns its place for several reasons.

  1. Define your own problem shape. Pick your own variables, ranges, and objectives. You are not limited to the categories Quick submissions list.
  2. Save your GA parameters once. When you run a saved problem, the GA settings you picked when building it become the defaults. You only override what changes for this run.
  3. One source of truth, many runs. Save a problem, then start a new run any time. Tweak generations or mutation for this run only; the saved problem stays the same so you can compare runs cleanly.
  4. Multi-objective without ceremony. Add more than one objective and the system switches to NSGA-II automatically. No need to remember which parent-selection type is allowed.
  5. See it before you run it. Each objective shows a live preview as you build, and a Generated fitness function panel shows the exact Python the GA will run. Wrong formulas surface in seconds, not after a full run.
  6. No code required for common shapes. Pick a library template (sum, target-matching, regression, constrained) and fill in inline parameters. Move to Custom code only when you need to.
  7. Code with confidence when you need to. When you switch to Custom code, the editor lists every variable name and the GA parameters you can reach via ga_instance. The code you write is the code the GA runs.

The Six Steps

The wizard walks you through six steps. You can move forwards and backwards freely, and you can jump straight to a step by clicking the label at the top. Nothing is saved until you reach Step 6 and choose Save without running or Save and run.

1. Basics

Give the problem a short, recognisable name. Add a description if you want a reminder of what it is for.

2. Genes

Each row on this step defines one gene, one value the GA will tune. Inside your fitness function, the genes arrive as the entries of solution in the order you list them here. The first gene becomes solution[0], the second solution[1], and so on.

Pick the type that matches each gene's search space:

  • Continuous (low/high) is the common case. Set a low and a high; optionally add a step to snap the gene to a regular grid.
  • List of values restricts the gene to a fixed set of numbers (use None to mean "unconstrained for this entry").
  • Integer range wraps range(start, stop) and optionally a step.
  • Linspace wraps numpy.linspace(start, stop, num).
  • Any leaves the gene unconstrained.

Tick Categorical on a gene whose values are categories with no order, for example a list 0, 1, 2 standing for three materials. The box is available for List of values, Integer range and Linspace genes, because a categorical gene needs a fixed set of values. Crossover and mutation then treat the values as separate choices instead of numbers that are close to or far from each other. You can also set this directly in Step 5 → Show advanced parameters → gene_categorical (override), which wins over the boxes.

Names must be valid Python identifiers like x, lr, or batch_size. Names cannot repeat within the same problem.

Names used by the generated function, such as solution, ga_instance, fitness_func, numpy, the listed formula functions, and names starting with _pb_ or _inner_, are reserved. Numeric inputs must be finite; range steps must be positive integers.

This step is a friendly wizard for PyGAD's gene_space. If you want raw control instead, leave the step minimal and write the gene_space directly in Step 5 → Show advanced parameters → gene_space (override). Whatever you put there wins over what this step derives.

Constants the fitness function uses but the GA does not tune belong in the next step (Problem parameters), not here.

3. Problem Parameters

Problem parameters are constants your fitness function uses alongside the genes. The GA does not optimise them; they stay fixed for the whole run. Reference them in formulas, library templates, or custom code by name.

For each parameter, give it a name (a valid Python identifier), pick a type, and set the value:

  • Number for a single float.
  • List of numbers for a 1-D array, written comma-separated (e.g. 1, 2, 3).
  • 2-D list of numbers for a matrix, one row per line.
  • String for a label.
  • Other (raw Python) when none of the above fits. Type any Python literal here (for example numpy.array([1, 2, 3]) or {"a": 1, "b": 2}); the wizard emits it verbatim into the rendered fitness source, so it is your responsibility to make sure it is valid Python.

Examples: a target value to match, an input matrix for a regression, a coefficient. If your fitness needs no constants, skip this step.

The wizard rejects names that clash with a gene's name because both end up as in-scope Python identifiers when the fitness function runs. This step is a friendly wizard for declaring constants once and reusing them across formulas, library templates, and custom code. If you prefer raw control, skip it and hard-code the same constants directly inside your Custom code in the next step.

4. Fitness Function

This is the single function the GA evaluates for every candidate. Each row in this step contributes one objective to that function. When you have more than one objective, the system combines them into one function that returns all the values together, and the GA switches to NSGA-II to balance them. A panel at the bottom of the step shows the generated Python source so you can see exactly what the GA will run.

The builder supplies the generated fitness callable automatically for both Save and run and new runs of saved problems. You do not need to enter a callable name for the combined function.

Each objective has:

  • Direction: Maximize or Minimize. The system handles the sign flip so your formula or code stays readable.
  • Source: Formula, Library template, or Custom code.

Formula mode lets you type a mathematical expression using the variable names from Step 2. For example, x**2 + y - 10. As you type, a preview evaluates the formula with each variable at the midpoint of its range. The allowed operators and functions are: + - * / **, abs, min, max, sum, round, pow, and your variable names.

Formulas can also index problem-parameter lists and matrices and use len. Live previews use bounded arithmetic: expressions are limited to 8192 characters, sequences to 10,000 items, and exponents to an absolute value of 1024. Large calculations and other Python belong in Custom code and run in the secure execution environment. Invalid expressions and non-finite results show a preview error.

Library template mode picks a built-in fitness function from a gallery: Sum of Genes, Reciprocal of Sum-of-Squares, Match a Target, Linear Regression Target, Regression error (1 / MSE), Constrained Sum. Most entries expose inline parameters you can tune without writing code (for example, the target value to match, the inputs and target vector for the regression entries, or the limit for the constrained sum). The Python source updates as you edit the parameters so there are no surprises.

Older saved library problems that store a template name use matching problem parameters as slot defaults; their saved per-objective overrides still win. Gallery examples carry their displayed Python source. Edit the constants in that source, or reference your Step 3 parameters there, when you want different values.

Click Browse & customize to open the gallery. It opens with the current template selected and the editor pre-filled. If you change the code, the row switches to Custom code mode with your edits in place. If you do not change the code, the row stays in Library template mode with the parameters you picked.

Custom code mode is for when you want to write the Python yourself. The editor lists which gene maps to each solution[i], which Problem parameters are in scope, and which GA parameters are accessible via ga_instance.*. Any Problem parameters you defined in Step 3 are emitted as top-level assignments so you can reference them by name. Define a callable taking (ga_instance, solution, solution_idx) and confirm its Callable name. Each objective row must return one finite number. Add rows for additional metrics; the Builder combines their values. Recursive functions retain their original name. In multi-objective problems, each custom or library objective has its own namespace for helpers, imports, and constants. Preview is not available for Custom code or Library templates; the actual run executes them in a secure environment.

Formula previews can use raw Python parameters that contain literals, such as dictionaries or lists. Parameters requiring Python execution are evaluated only during a run. A formula that does not reference such a parameter can still be previewed.

5. GA Parameters

The genetic algorithm has a handful of knobs that control how it searches. The defaults are sensible for a first run; tweak from there if you need to. Every knob has a small help icon next to it that explains what it does.

The wizard exposes:

  • Number of generations
  • Population size
  • Number of parents mating
  • Mutation type
  • Crossover type
  • Parent selection type

Click Show advanced parameters to reveal more controls (probabilities, keep parents, keep elitism, K-tournament, init range, save flags, stop criteria, and a builder for the initial population). The advanced section also lets you override the auto-derived gene space with a custom one using the same visual builder available on the New Submission form, and it exposes the seven lifecycle callbacks (on_start, on_fitness, on_parents, on_crossover, on_mutation, on_generation, on_stop). Each callback is optional; leave a field blank to skip it. The same scope hints as Step 3 are shown next to each callback so you always know what is available.

For adaptive mutation, enter a pair in exactly one mutation control, such as [2, 1] for the number of mutated genes, [20, 5] for percentages, or [0.2, 0.05] for probabilities. Other mutation types take a single number. Batched fitness evaluation preserves the one-candidate contract of each objective and returns one value per candidate, or one objective vector per candidate for multi-objective runs.

The wizard checks two rules for you:

  • The number of parents mating cannot be larger than the population size.
  • Multi-objective runs use NSGA-II for parent selection.

6. Review and Save

The last step shows everything you defined in one place. Each card has an Edit link that jumps you back to the relevant step. When you are happy:

  • Save without running stores the problem under My problems without using any of your run budget. You can come back and run it any time.
  • Save and run stores the problem and immediately starts a run. You land on the live result page where you can watch the generations tick by.

Running a Saved Problem

Open My problems and click New run on the card. You land on a two-section page:

  • Problem definition is read-only here. It shows the genes, problem parameters, and objectives you saved. Use Edit problem if you want to change them.
  • GA parameters are pre-filled with the values you saved with the problem. Override anything for this run; the saved defaults stay the same.

Clear an optional field to omit that setting for the new run, including a seed, probability or callback. New runs keep a copy of their problem definition, so result labels and constants remain accurate after you edit or delete the saved problem. Reexecution and continuation retain that same definition. Older runs created before this change use their linked template when it is available; their generated fitness source remains the original execution source.

Click Run to start the run. Every run is a normal submission and appears in your usual User submissions list with full results and history.

Click Edit instead of New run when you want to change the problem itself. The wizard opens with all your saved values pre-filled.

When to Write Code Instead

The Problem Builder is intentionally focused. If your fitness function needs to load a dataset, call a Python library, or run anything more complex than what the library templates cover, the New submission form is the right path. There you can paste a full Python function and use every parameter the GA supports. Custom code mode in the Problem Builder is a good middle ground: write the function inline and keep the saved-defaults benefit of a stored problem.

Thanks for the feedback!