This chapter introduces class functions and group characters in **GAP3**.

First section Why Group Characters tells about the ideas why to use these structures besides the characters and character tables described in chapters Character Tables and Characters.

The subsequent section More about Class Functions tells details about
the implementation of group characters and class functions in **GAP3**.

Sections Operators for Class Functions and Functions for Class Functions tell about the operators and functions for class functions and (virtual) characters.

Sections ClassFunction, VirtualCharacter, Character, and Irr describe how to construct such class functions and group characters.

Sections IsClassFunction, IsVirtualCharacter, and IsCharacter describe the characteristic functions of class functions and virtual characters.

Then sections InertiaSubgroup and OrbitsCharacters describe other functions for characters.

Then sections Storing Subgroup Information, NormalSubgroupClasses, ClassesNormalSubgroup, and FactorGroupNormalSubgroupClasses tell about some functions and record components to access and store frequently used (normal) subgroups.

The final section Class Function Records describes the records that implement class functions.

In this chapter, all examples use irreducible characters of the
symmetric group *S _{4}*. For running the examples, you must first
define the group and its characters as follows.

gap> S4:= SolvableGroup( "S4" );; gap> irr:= Irr( S4 );;

- Why Group Characters
- More about Class Functions
- Operators for Class Functions
- Functions for Class Functions
- ClassFunction
- VirtualCharacter
- Character
- IsClassFunction
- IsVirtualCharacter
- IsCharacter
- Irr
- InertiaSubgroup
- OrbitsCharacters
- Storing Subgroup Information
- NormalSubgroupClasses
- ClassesNormalSubgroup
- FactorGroupNormalSubgroupClasses
- Class Function Records

When one says ``*χ* is a character of a group *G*'' then this object
*χ* carries a lot of information. *χ* has certain properties such as
being irreducible or not. Several subgroups of *G* are related to *χ*,
such as the kernel and the centre of *χ*. And one can apply operators
to *χ*, such as forming the conjugate character under the action of an
automorphism of *G*, or computing the determinant of *χ*.

In **GAP3**, the characters known from chapters Character Tables and
Characters are just lists of character values. This has several
disadvantages. Firstly one cannot store knowledge about a character
directly in the character, and secondly for every computation that requires
more than just the character values one has to regard this list explicitly as
a character belonging to a character table.
In practice this means that the user has the task to put the objects into
the right context, or --more concrete-- the user has to supply lots of
arguments.

This works nicely for characters that are used without groups, like characters of library tables. And if one deals with incomplete character tables often it is necessary to specify the arguments explicitly, for example one has to choose a fusion map or power map from a set of possibilities.

But for dealing with a group and its characters, and maybe also subgroups
and their characters, it is desirable that **GAP3** keeps track of the
interpretation of characters.

Because of this it seems to be useful to introduce an alternative concept
where a group character in **GAP3** is represented as a record that contains
the character values, the underlying group or character table, an
appropriate operations record, and all the knowledge about the group
character.

Together with characters, also the more general class functions and virtual characters are implemented.

Here is an **example** that shows both approaches.
First we define the groups.

gap> S4:= SolvableGroup( "S4" );; gap> D8:= SylowSubgroup( S4, 2 );; D8.name:= "D8";;

We do some computations using the functions described in chapters Characters and Character Tables.

gap> t := CharTable( S4 );; gap> tD8 := CharTable( D8 );; gap> FusionConjugacyClasses( D8, S4 );; gap> chi:= tD8.irreducibles[2]; [ 1, -1, 1, 1, -1 ] gap> Tensored( [ chi ], [ chi ] )[1]; [ 1, 1, 1, 1, 1 ] gap> ind:= Induced( tD8, t, [ chi ] )[1]; [ 3, -1, 0, 1, -1 ] gap> List( t.irreducibles, x -> ScalarProduct( t, x, ind ) ); [ 0, 0, 0, 1, 0 ] gap> det:= DeterminantChar( t, ind ); [ 1, 1, 1, -1, -1 ] gap> cent:= CentralChar( t, ind ); [ 1, -1, 0, 2, -2 ] gap> rest:= Restricted( t, tD8, [ cent ] )[1]; [ 1, -1, -1, 2, -2 ]

And now we do the same calculations with the class function records.

gap> irr := Irr( S4 );; gap> irrD8 := Irr( D8 );; gap> chi:= irrD8[2]; Character( D8, [ 1, -1, 1, 1, -1 ] ) gap> chi * chi; Character( D8, [ 1, 1, 1, 1, 1 ] ) gap> ind:= chi ^ S4; Character( S4, [ 3, -1, 0, 1, -1 ] ) gap> List( irr, x -> ScalarProduct( x, ind ) ); [ 0, 0, 0, 1, 0 ] gap> det:= Determinant( ind ); Character( S4, [ 1, 1, 1, -1, -1 ] ) gap> cent:= Omega( ind ); ClassFunction( S4, [ 1, -1, 0, 2, -2 ] ) gap> rest:= Character( D8, cent ); Character( D8, [ 1, -1, -1, 2, -2 ] )

Of course we could have used the `Induce`

and `Restricted`

function
also for lists of class functions.

gap> Induced( tD8, t, tD8.irreducibles{ [ 1, 3 ] } ); [ [ 3, 3, 0, 1, 1 ], [ 3, 3, 0, -1, -1 ] ] gap> Induced( irrD8{ [ 1, 3 ] }, S4 ); [ Character( S4, [ 3, 3, 0, 1, 1 ] ), Character( S4, [ 3, 3, 0, -1, -1 ] ) ]

If one deals with complete character tables then often the table provides enough information, so it is possible to use the table instead of the group.

gap> s5 := CharTable( "A5.2" );; irrs5 := Irr( s5 );; gap> m11:= CharTable( "M11" );; irrm11:= Irr( m11 );; gap> irrs5[2]; Character( CharTable( "A5.2" ), [ 1, 1, 1, 1, -1, -1, -1 ] ) gap> irrs5[2] ^ m11; Character( CharTable( "M11" ), [ 66, 2, 3, -2, 1, -1, 0, 0, 0, 0 ] ) gap> Determinant( irrs5[4] ); Character( CharTable( "A5.2" ), [ 1, 1, 1, 1, -1, -1, -1 ] )

In this case functions that compute **normal** subgroups related to
characters will return the list of class positions corresponding to that
normal subgroup.

gap> Kernel( irrs5[2] ); [ 1, 2, 3, 4 ]

But if we ask for non-normal subgroups of course there is no chance to get an answer without the group, for example inertia subgroups cannot be computed from character tables.

Let *G* be a finite group. A **class function** of *G* is a function from
*G* into the complex numbers (or a subfield of the complex numbers) that is
constant on conjugacy classes of *G*.
Addition, multiplication, and scalar multiplication of class functions are
defined pointwise. Thus the set of all class functions of *G* is an
algebra (or ring, or vector space).

**Class functions and (virtual) group characters**

Every mapping with source *G* that is constant on conjugacy classes of *G*
is called a **class function** of *G*.
Differences of characters of *G* are called **virtual characters** of *G*.

Class functions occur in a natural way when one deals with characters. For example, the central character of a group character is only a class function.

Every character is a virtual character, and every virtual character is a
class function.
Any function or operator that is applicable to a class function can of
course be applied to a (virtual) group character. There are functions
only for (virtual) group characters, like `IsIrreducible`

, which doesn't
make sense for a general class function, and there are also functions
that do not make sense for virtual characters but only for characters,
like `Determinant`

.

**Class functions as mappings**

In **GAP3**, class functions of a group *G* are mappings (see chapter
Mappings) with source *G* and range `Cyclotomics`

(or a subfield).
All operators and functions for mappings (like Image `Image`

, PreImages
`PreImages`

) can be applied to class functions.

**Note**, however, that the operators `*`

and `^`

allow also other
arguments than mappings do (see Operators for Class Functions).

`chi` = `psi`

`chi` < `psi`

Equality and comparison of class functions are defined as for mappings
(see Comparisons of Mappings); in case of equal source and range the
`values`

components are used to compute the result.

gap> irr[1]; irr[2]; Character( S4, [ 1, 1, 1, 1, 1 ] ) Character( S4, [ 1, 1, 1, -1, -1 ] ) gap> irr[1] < irr[2]; false gap> irr[1] > irr[2]; true gap> irr[1] = Irr( SolvableGroup( "S4" ) )[1]; false # The groups are different.

`chi` + `psi`

`chi` - `psi`

`+`

and `-`

denote the addition and subtraction of class functions.

`n` * `chi`

`chi` * `psi`

`*`

denotes (besides the composition of mappings,
see Operations for Mappings) the multiplication of a class function
`chi` with a scalar `n` and the tensor product of two class functions.

`chi` / `n`

`/`

denotes the division of the class function `chi` by a scalar `n`.

gap> psi:= irr[3] * irr[4]; Character( S4, [ 6, -2, 0, 0, 0 ] ) gap> psi:= irr[3] - irr[1]; VirtualCharacter( S4, [ 1, 1, -2, -1, -1 ] ) gap> phi:= psi * irr[4]; VirtualCharacter( S4, [ 3, -1, 0, -1, 1 ] ) gap> IsCharacter( phi ); phi; true Character( S4, [ 3, -1, 0, -1, 1 ] ) gap> psi:= ( 3 * irr[2] - irr[3] ) * irr[4]; VirtualCharacter( S4, [ 3, -1, 0, -3, 3 ] ) gap> 2 * psi ; VirtualCharacter( S4, [ 6, -2, 0, -6, 6 ] ) gap> last / 3; ClassFunction( S4, [ 2, -2/3, 0, -2, 2 ] )

`chi` ^ `n`

`g` ^ `chi`

denote the tensor power by a nonnegative integer `n` and the image of the
group element `g`, like for all mappings (see Operations for Mappings).

`chi` ^ `g`

is the conjugate class function by the group element `g`, that must
be an element of the parent of the source of `chi` or something else that
acts on the source via `^`

.
If

is not a permutation group then `chi`.source`g` may also be a
permutation that is interpreted as acting by permuting the classes
(This maybe useful for table characters.).

`chi` ^ `G`

is the induced class function.

gap> V4:= Subgroup( S4, S4.generators{ [ 3, 4 ] } ); Subgroup( S4, [ c, d ] ) gap> V4.name:= "V4";; gap> V4irr:= Irr( V4 );; gap> chi:= V4irr[3]; Character( V4, [ 1, -1, 1, -1 ] ) gap> chi ^ S4; Character( S4, [ 6, -2, 0, 0, 0 ] ) gap> chi ^ S4.2; Character( V4, [ 1, -1, -1, 1 ] ) gap> chi ^ ( S4.2 ^ 2 ); Character( V4, [ 1, 1, -1, -1 ] ) gap> S4.3 ^ chi; S4.4 ^ chi; 1 -1 gap> chi ^ 2; Character( V4, [ 1, 1, 1, 1 ] )

Besides the usual **mapping functions** (see chapter Mappings for
the details.), the following polymorphic functions are overlaid in
the `operations`

records of class functions and (virtual) characters.
They are listed in alphabetical order.

`Centre(`

:`chi`)-

centre of a class function

`Constituents(`

:`chi`)-

set of irreducible characters of a virtual character

`Degree(`

:`chi`)-

degree of a class function

`Determinant(`

:`chi`)-

determinant of a character

`Display(`

:`chi`)-

displays the class function with the table head

`Induced(`

:`list`,`G`)-

induced class functions corresp. to class functions in the list`list`from subgroup`H`to group`G`

`IsFaithful(`

:`chi`)-

property check (virtual characters only)

`IsIrreducible(`

:`chi`)-

property check (characters only)

`Kernel(`

:`chi`)-

kernel of a class function

`Norm(`

:`chi`)-

norm of class function

`Omega(`

:`chi`)-

central character

`Print(`

:`chi`)-

prints a class function

`Restricted(`

:`list`,`H`)-

restrictions of class functions in the list`list`to subgroup`H`

`ScalarProduct(`

:`chi`,`psi`)-

scalar product of two class functions

`ClassFunction( `

`G`, `values` )

returns the class function of the group `G` with values list `values`.

`ClassFunction( `

`G`, `chi` )

returns the class function of `G` corresponding to the class function
`chi` of *H*. The group *H* can be a factor group of `G`, or `G` can be
a subgroup or factor group of *H*.

gap> phi:= ClassFunction( S4, [ 1, -1, 0, 2, -2 ] ); ClassFunction( S4, [ 1, -1, 0, 2, -2 ] ) gap> coeff:= List( irr, x -> ScalarProduct( x, phi ) ); [ -1/12, -1/12, -1/6, 5/4, -3/4 ] gap> ClassFunction( S4, coeff ); ClassFunction( S4, [ -1/12, -1/12, -1/6, 5/4, -3/4 ] ) gap> syl2:= SylowSubgroup( S4, 2 );; gap> ClassFunction( syl2, phi ); ClassFunction( D8, [ 1, -1, -1, 2, -2 ] )

`VirtualCharacter( `

`G`, `values` )

returns the virtual character of the group `G` with values list `values`.

`VirtualCharacter( `

`G`, `chi` )

returns the virtual character of `G` corresponding to the virtual character
`chi` of *H*. The group *H* can be a factor group of `G`, or `G` can be
a subgroup or factor group of *H*.

gap> syl2:= SylowSubgroup( S4, 2 );; gap> psi:= VirtualCharacter( S4, [ 0, 0, 3, 0, 0 ] ); VirtualCharacter( S4, [ 0, 0, 3, 0, 0 ] ) gap> VirtualCharacter( syl2, psi ); VirtualCharacter( D8, [ 0, 0, 0, 0, 0 ] ) gap> S3:= S4 / V4; Group( a, b ) gap> VirtualCharacter( S3, irr[3] ); VirtualCharacter( Group( a, b ), [ 2, -1, 0 ] )

**Note** that it is not checked whether the result is really a virtual
character.

`Character( `

`repres` )

returns the character of the group representation `repres`.

`Character( `

`G`, `values` )

returns the character of the group `G` with values list `values`.

`Character( `

`G`, `chi` )

returns the character of `G` corresponding to the character
`chi` with source *H*.
The group *H* can be a factor group of `G`, or `G` can be
a subgroup or factor group of *H*.

gap> syl2:= SylowSubgroup( S4, 2 );; gap> Character( syl2, irr[3] ); Character( D8, [ 2, 2, 2, 0, 0 ] ) gap> S3:= S4 / V4; Group( a, b ) gap> Character( S3, irr[3] ); Character( Group( a, b ), [ 2, -1, 0 ] ) gap> reg:= Character( S4, [ 24, 0, 0, 0, 0 ] ); Character( S4, [ 24, 0, 0, 0, 0 ] )

**Note** that it is not checked whether the result is really a
character.

`IsClassFunction( `

`obj` )

returns `true`

if `obj` is a class function, and `false`

otherwise.

gap> chi:= S4.charTable.irreducibles[3]; [ 2, 2, -1, 0, 0 ] gap> IsClassFunction( chi ); false gap> irr[3]; Character( S4, [ 2, 2, -1, 0, 0 ] ) gap> IsClassFunction( irr[3] ); true

`IsVirtualCharacter( `

`obj` )

returns `true`

if `obj` is a virtual character, and `false`

otherwise.
For a class function `obj` that does not know whether it is a virtual
character, the scalar products with all irreducible characters of the
source of `obj` are computed. If they are all integral then
`obj` is turned into a virtual character record.

gap> psi:= irr[3] - irr[1]; VirtualCharacter( S4, [ 1, 1, -2, -1, -1 ] ) gap> cf:= ClassFunction( S4, [ 1, 1, -2, -1, -1 ] ); ClassFunction( S4, [ 1, 1, -2, -1, -1 ] ) gap> IsVirtualCharacter( cf ); true gap> IsCharacter( cf ); false gap> cf; VirtualCharacter( S4, [ 1, 1, -2, -1, -1 ] )

`IsCharacter( `

`obj` )

returns `true`

if `obj` is a character, and `false`

otherwise.
For a class function `obj` that does not know whether it is a
character, the scalar products with all irreducible characters of the
source of `obj` are computed. If they are all integral and nonegative then
`obj` is turned into a character record.

gap> psi:= ClassFunction( S4, S4.charTable.centralizers ); ClassFunction( S4, [ 24, 8, 3, 4, 4 ] ) gap> IsCharacter( psi ); psi; true Character( S4, [ 24, 8, 3, 4, 4 ] ) gap> cf:= ClassFunction( S4, irr[3] - irr[1] ); ClassFunction( S4, [ 1, 1, -2, -1, -1 ] ) gap> IsCharacter( cf ); cf; false VirtualCharacter( S4, [ 1, 1, -2, -1, -1 ] )

`Irr( `

`G` )

returns the list of irreducible characters of the group `G`.
If necessary the character table of `G` is computed.
The succession of characters is the same as in `CharTable( `

.
`G` )

gap> Irr( SolvableGroup( "S4" ) ); [ Character( S4, [ 1, 1, 1, 1, 1 ] ), Character( S4, [ 1, 1, 1, -1, -1 ] ), Character( S4, [ 2, 2, -1, 0, 0 ] ), Character( S4, [ 3, -1, 0, 1, -1 ] ), Character( S4, [ 3, -1, 0, -1, 1 ] ) ]

`InertiaSubgroup( `

`G`, `chi` )

For a class function `chi` of a normal subgroup *N* of the group `G`,
`InertiaSubgroup( `

returns the inertia subgroup `G`, `chi` )*I _{G}(chi)*,
that is, the subgroup of all those elements

gap> V4:= Subgroup( S4, S4.generators{ [ 3, 4 ] } ); Subgroup( S4, [ c, d ] ) gap> irrsub:= Irr( V4 ); #W Warning: Group has no name [ Character( Subgroup( S4, [ c, d ] ), [ 1, 1, 1, 1 ] ), Character( Subgroup( S4, [ c, d ] ), [ 1, 1, -1, -1 ] ), Character( Subgroup( S4, [ c, d ] ), [ 1, -1, 1, -1 ] ), Character( Subgroup( S4, [ c, d ] ), [ 1, -1, -1, 1 ] ) ] gap> List( irrsub, x -> InertiaSubgroup( S4, x ) ); [ Subgroup( S4, [ a, b, c, d ] ), Subgroup( S4, [ a*b^2, c, d ] ), Subgroup( S4, [ a*b, c, d ] ), Subgroup( S4, [ a, c, d ] ) ]

`OrbitsCharacters( `

`irr` )

returns a list of orbits of the characters `irr` under the action of
Galois automorphisms and multiplication with linear characters in `irr`.
This is used for functions that need to consider only representatives
under the operation of this group, like TestSubnormallyMonomial.

`OrbitsCharacters`

works also for `irr` a list of character value lists.
In this case the result contains orbits of these lists.

**Note** that `OrbitsCharacters`

does not require that `irr` is closed
under the described action, so the function may also be used to
**complete** the orbits.

gap> irr:= Irr( SolvableGroup( "S4" ) );; gap> OrbitsCharacters( irr ); [ [ Character( S4, [ 1, 1, 1, -1, -1 ] ), Character( S4, [ 1, 1, 1, 1, 1 ] ) ], [ Character( S4, [ 2, 2, -1, 0, 0 ] ) ], [ Character( S4, [ 3, -1, 0, -1, 1 ] ), Character( S4, [ 3, -1, 0, 1, -1 ] ) ] ] gap> OrbitsCharacters( List( irr{ [1,2,4] }, x -> x.values ) ); [ [ [ 1, 1, 1, -1, -1 ], [ 1, 1, 1, 1, 1 ] ], [ [ 3, -1, 0, 1, -1 ], [ 3, -1, 0, -1, 1 ] ] ]

Many computations for a group character *χ* of a group *G*, such as that
of kernel or centre of *χ*, involve computations in (normal) subgroups or
factor groups of *G*.

There are two aspects that make it reasonable to store relevant information used in these computations.

First it is possible to use the character table of a group for computations
with the group. For example, suppose we know for every normal subgroup *N*
the list of positions of conjugacy classes that form *N*. Then we can
compute the intersection of normal subgroups efficiently by intersecting
the corresponding lists.

Second one should try to reuse (expensive) information one has computed.
Suppose you need the character table of a certain subgroup *U* that was
constructed for example as inertia subgroup of a character. Then it may be
probable that this group has been constructed already. So one should look
whether *U* occurs in a list of interesting subgroups for that the tables
are already known.

This section lists several data structures that support storing and using information about subgroups.

**Storing Normal Subgroup Information**

In some cases a question about a normal subgroup *N* can be answered
efficiently if one knows the character table of *G* and the *G*-conjugacy
classes that form *N*, e.g., the question whether a character of *G*
restricts irreducibly to *N*.
But other questions require the computation of the group *N* or even more
information, e.g., if we want to know whether a character restricts
homogeneously to *N* this will in general require the computation of the
character table of *N*.

In order to do such computations only once, we introduce three components
in the group record of *G* to store normal subgroups, the corresponding
lists of conjugacy classes, and (if known) the factor groups, namely

`nsg`

:-

a list of (not necessarily all) normal subgroups of*G*,

`nsgclasses`

:-

at position*i*the list of positions of conjugacy classes forming the*i*-th entry of the`nsg`

component,

`nsgfactors`

:-

at position*i*(if bound) the factor group modulo the*i*-th entry of the`nsg`

component.

The functions

`NormalSubgroupClasses`

,

`FactorGroupNormalSubgroupClasses`

,

`ClassesNormalSubgroup`

initialize these components and update them. They are the only functions that do this.

So if you need information about a normal subgroup of *G* for that you know
the *G*-conjugacy classes, you should get it using `NormalSubgroupClasses`

.
If the normal subgroup was already stored it is just returned, with all the
knowledge it contains. Otherwise the normal subgroup is computed and
added to the lists, and will be available for the next call.

**Storing information for computing conjugate class functions**

The computation of conjugate class functions requires the computation of
permutatins of the list of conjugacy classes. In order to minimize the
number of membership tests in conjugacy classes it is useful to store
a partition of classes that is respected by every admissible permutation.
This is stored in the component `globalPartitionClasses`

.

If the normalizer *N* of *H* in its parent is stored in *H*, or if *H* is
normal in its parent then the component `permClassesHomomorphism`

is used.
It holds the group homomorphism mapping every element of *N* to the
induced permutation of classes.

Both components are generated automatically when they are needed.

**Storing inertia subgroup information**

Let *N* be the normalizer of *H* in its parent, and *χ* a character
of *H*. The inertia subgroup *I _{N}(χ)* is the stabilizer
in

`inertiaInfo`

component of `partitions`

and `stabilizers`

, both lists.
The `stabilizers`

component contains the stabilizer in
`NormalSubgroupClasses( `

`G`, `classes` )

returns the normal subgroup of the group `G` that consists of the
conjugacy classes whose positions are in the list `classes`.

If

does not contain the required normal subgroup, and if `G`.nsg*G*
contains the component

then the result and the
group in `G`.normalSubgroups

will be identical.
`G`.normalSubgroups

gap> ccl:= ConjugacyClasses( S4 ); [ ConjugacyClass( S4, IdAgWord ), ConjugacyClass( S4, d ), ConjugacyClass( S4, b ), ConjugacyClass( S4, a ), ConjugacyClass( S4, a*d ) ] gap> NormalSubgroupClasses( S4, [ 1, 2 ] ); Subgroup( S4, [ c, d ] )

The list of classes corresponding to a normal subgroup is returned by ClassesNormalSubgroup.

`ClassesNormalSubgroup( `

`G`, `N` )

returns the list of positions of conjugacy classes of the group `G` that
are contained in the normal subgroup `N` of `G`.

gap> ccl:= ConjugacyClasses( S4 ); [ ConjugacyClass( S4, IdAgWord ), ConjugacyClass( S4, d ), ConjugacyClass( S4, b ), ConjugacyClass( S4, a ), ConjugacyClass( S4, a*d ) ] gap> V4:= NormalClosure( S4, Subgroup( S4, [ S4.4 ] ) ); Subgroup( S4, [ c, d ] ) gap> ClassesNormalSubgroup( S4, V4 ); [ 1, 2 ]

The normal subgroup corresponding to a list of classes is returned by NormalSubgroupClasses.

`FactorGroupNormalSubgroupClasses( `

`G`, `classes` )

returns the factor group of the group `G` modulo the normal subgroup of
`G` that consists of the conjugacy classes whose positions are in the
list `classes`.

gap> ccl:= ConjugacyClasses( S4 ); [ ConjugacyClass( S4, IdAgWord ), ConjugacyClass( S4, d ), ConjugacyClass( S4, b ), ConjugacyClass( S4, a ), ConjugacyClass( S4, a*d ) ] gap> S3:= FactorGroupNormalSubgroupClasses( S4, [ 1, 2 ] ); Group( a, b )

Every class function has the components

`isClassFunction`

:-

always`true`

,

`source`

:-

the underlying group (or character table),

`values`

:-

the list of values, corresponding to the`conjugacyClasses`

component of`source`

,

`operations`

:-

the operations record which is one of`ClassFunctionOps`

,`VirtualCharacterOps`

,`CharacterOps`

.

Optional components are

`isVirtualCharacter`

:-

The class function knows to be a virtual character.

`isCharacter`

:-

The class function knows to be a character.

gap3-jm

24 Apr 2021