Remove Elements from a Set

The empty statement in AIMMS is used to clear the contents of a set or reset values of identifiers within a subset of predefined sets. Its behavior depends on the type of set being emptied:

  • The set is not a subset of AllIdentifiers: the empty statement will remove all elements from the given set.

  • The set is a subset of AllIdentifiers: the empty statement will empty all the identifiers that are in the given subset.

Clearing a Regular Set vs. a Subset of AllVariables

Let’s assume the following two identifiers:

Set NormalSet;

Set ActiveVariables {
  SubsetOf: AllVariables;
}

As you can see, it holds that ActiveVariables \(\subseteq\) AllVariables \(\subseteq\) AllIdentifiers because the predefined set AllVariables is defined in AIMMS to be a subset of AllVariablesConstraints, which in turn is a subset of AllIdentifiers. You can verify this by opening the attribute window of these predefined sets.

This means that the empty statement behaves differently for NormalSet and ActiveVariables, as explained below:

1!This will remove all elements from the set NormalSet
2empty NormalSet ;
3
4!This will clear the values of all variables in the subset ActiveVariables
5!After the empty statement, the set itself will still contain elements!
6empty ActiveVariables ;
7
8!This will actually remove all elements from the set ActiveVariables
9ActiveVariables := {} ;

empty vs. := {} on a Regular Set

For a set that is not a subset of AllIdentifiers, both empty s_A and s_A := {} leave the set without elements, but they do not treat the data defined over it the same way.

Assume the following declarations, where p_B has data:

Set s_A {
  Index : i_a;
}

Parameter p_B {
  IndexDomain : i_a;
}

After empty, the data of p_B is gone:

1empty s_A ;   ! s_A has no elements, and all data of p_B is removed

After assigning the empty set, p_B only looks empty:

1s_A := {} ;   ! s_A has no elements, and the data of p_B becomes inactive

The values of p_B are still stored, but they are inactive: no element of s_A refers to them, so they do not show up in displays, pages or expressions. Restoring s_A to its previous contents makes the data of p_B visible again.

Choose the form that matches your intent:

  • Use empty s_A when you want the set and everything defined over it cleared, for instance before reading a new data instance.

  • Use s_A := {} when you want to hide the data temporarily and bring it back by restoring the elements later. Keep in mind that inactive data still occupies memory until it is removed.

If you decide later that the inactive data is no longer needed, remove it explicitly. Cleanup p_B ; drops the inactive values from p_B alone, and CleanDependents s_A ; does the same across every identifier defined over s_A. After either statement, restoring the elements of s_A no longer brings the old values back. See Reclaim Memory Between Data Instances for how these statements compare and what they do to memory.

A Defined Set Cannot Be Emptied At All

There is a third case. If a set was declared with a Definition attribute, its contents are computed from that definition rather than stored as data the model owns, and neither form above applies:

1empty MySet ;

fails with

The defined domain set "MySet" cannot be emptied

This is not a defect. A defined set is recomputed automatically whenever the identifiers its definition depends on change, so there is no independently stored content for a procedural statement to clear.

If what you need is a set that can be reset and repopulated between runs - to keep elements from a previous execution out of the next one, for instance - declare it without a Definition attribute and populate it explicitly, with SetElementAdd or an assignment. A set’s contents can only be assigned or reset procedurally when it is not a defined set.

Empty Every Set Except a Named Few

Clearing every set you declared, except one or two, is a subset construction rather than a list. The second case above is what makes it work: empty applied to a subset of AllIdentifiers empties the identifiers that the subset contains.

First capture the scope:

Set s_declaredSets {
  SubsetOf : AllIdentifiers;
  Index    : i_sds;
}

Then:

1s_declaredSets := MySection * AllSets;

AllSets is the predeclared subset of AllIdentifiers holding every declared set in the project. The name of a Section node is also available as an implicit subset of AllIdentifiers, containing every identifier declared beneath that node, so intersecting the two restricts the result to the sets declared in that section.

Use a section rather than the whole model. That is what keeps the statement from reaching sets that belong to a library you did not write.

Then filter out the exceptions:

Set s_setsToEmpty {
  SubsetOf : s_declaredSets;
}

Then:

1s_setsToEmpty := s_declaredSets - { 's_keepThisOne' };

The elements of AllIdentifiers are the identifier names themselves, so a set difference against an element literal is enough. Add further exceptions inside the braces. The literal has to name an identifier that exists, otherwise AIMMS rejects it at compile time.

And clear them in one statement:

1empty s_setsToEmpty ;

Naming the exceptions, rather than the sets to clear, is almost always the intent: a set added next month is then cleared automatically. Listing the sets to clear does the opposite, and the omission surfaces later as data surviving a reset that should have removed it.

Key Takeaways

  • The empty statement removes elements from general sets but only clears values for subsets of predefined sets.

  • To fully remove elements from a subset of AllIdentifiers, assign an empty set {} to it explicitly.

  • On a regular set, empty s_A also removes the data of identifiers defined over s_A, while s_A := {} only makes that data inactive; restoring the elements makes it visible again.

  • A set with a Definition attribute cannot be emptied by any means; drop the definition if the set has to be procedurally editable.

  • To clear many sets at once, intersect a Section name with AllSets and subtract the exceptions, then pass the result to empty. Naming the exceptions keeps new sets covered automatically.

  • Use empty carefully when dealing with predefined sets to avoid unintended behavior.