Questaal Home
Navigation

The mcx matrix calculator

mcx is a stack-based matrix calculator. Two-dimensional matrices are read from disk files (or generated by other constructs) and pushed onto a stack. Unary operations (such as inversion or scaling by a constant) manipulate the top array on the stack. Binary operations (such as addition) operate on the top two elements on the stack.

mcx does not manipulate symbolic matrices, but will in many places convert expressions from user-defined and other internally generated variables, such as the number of rows or columns of an array.

See Instruction Summary for a listing of all mcx instructions.

Table of Contents


Preliminaries

The calculator manipulates array elements on the stack. The most recent, or top-level array is called s0; arrays deeper in the stack are called s1, s2, ….

Arrays are normally read from disk files, which have the standard Questaal format, and a few other formats. Data parsed in files makes use of the programming language capabilities of the preprocessor.

mcx is required and is assumed to be in your path. This manual is written for version 1.062. To see what version you are using, do:

$ mcx --version

See Instruction Summary.

1. Introduction

mcx is a matrix extension of an ordinary calculator. It is mainly designed to work with 2D arrays; it operates on numerical arrays. It is command-line driven and can efficiently manipulate arrays for analysis. Some Questaal testing scripts make use of it to analyze whether a test passes a certain criterion.

Usually arrays are read from disk files in ASCII format, though mcx can read binary files, and has limited ability to create arrays from command-line arguments (see for example the –array and -1 constructs). mcx is stack-based: each time you read an array from a file (or create a new array by some other means) it is pushed onto the stack. Arrays are called s0, s1, s2, ….

You read an array from disk by naming the file in a command-line argument, e.g. mcx h attempts to read an array from file h. The contents are parsed and if the reading is successful, pushed on the stack, becoming array s0. The old s0 becomes s1, the old s1 becomes s2, etc. The ASCII format of the file is quite flexible; you can specify the number of rows nr and number of columns nc in a number of ways:

  1. You can specify the number of columns on the command line, with −nc=#; similarly with the number of rows (−nr=#). −nc=#; this switch is used in Example 2.2.

  2. You can include a directive at the start of the file, before any data is read. mcx passes the input through a file preprocessor first; in addition a directive specifying some combination nr and nc, e.g.

     % rows #1  cols #2
    

    supplies the needed information to mcx.

  3. In the absence of an explicit specification, mcx will infer nc by counting how many numbers (more generally expressions) are on the first line.

If nc is obtained somehow but not nr, mcx determines it by counting the number of expressions in the entire file and dividing by nc.

Note: : if the −nc=# or −nr=# switches are not used, mcx determines them from the standard Questaal algorithm for reading 2D arrays, described in more detail here.

1.1 Named arrays

You can copy s0 to a permanent array with a name. It remains fixed as the stack varies. To push it onto the stack, refer to by using the array name a command-line argument. If the name is found among the list of permanent arrays, it will push the internally named array onto the stack, rather than try to read a file of that name.

For example suppose files h and s contain arrays. The command

mcx h -a h  s -a s  s h -show

does the following:

  • Loads the contents of file h onto the stack. It becomes s0.
  • Copies s0 to an internal array named h and pops s0 off the stack.
  • Loads the contents of file s onto the stack. It becomes s0.
  • Copies s0 to an internal array named s and pops it off the stack.
  • Pushes the contents of internal array s onto the stack.
  • Pushes the contents of internal array h onto the stack.
  • Lists permanent and stack arrays (there are two of each), and their attributes.

See Instruction Summary.

2. Examples

This section develops a few examples to provide an intuitive feel for how mcx works and to illustrate some features.
A systematic description of mcx’s features and arguments is given in Section 3.

Cut and paste the following data into array into file mat1

1.1 2.2
3.3 4.4

and this data into file mat2.

5 6
7 8

Example 2.1.   Add mat1 to mat2

If you do the following:
mcx mat1 mat2 -+
you should see

% rows 2 cols 2 real
    6.100000    8.200000
   10.300000   12.400000

Any argument that begins with  “−“  is a switch or an operator (as distinct from data). The string following  “−“  names the operator.
Thus:

  • mat1 : reads file mat1 from disk and pushes it onto the stack; call it s0.

  • mat2 : reads file mat2 and pushes it onto the stack so s0s1 and the contents of mat2s0.

  • −+ : is the binary operation “add.” If s0 and s1 exist, they are summed and popped off the stack. Their sum is pushed onto top-level array s0.

Note: if operations occur before arrays are given, they are push on an operations stack and execute when arrays become available. The following commands accomplish the same thing

$ mcx -+ mat1 mat2
$ mcx mat1 -+ mat2
$ mcx mat1 mat2 -+

Use −show to see the stack. Try this
mcx -f2f8.1 mat1 mat2 -show -+`
You should get

# 0 named arrays, 2 on stack; pending 0 unops 0 bops (vsn 1.057)
# stack             nr    nc   cast
#    2               2     2   real
#    1               2     2   real
% rows 2 cols 2 real
     6.1     8.2
    10.3    12.4

−show prints out what arrays are in the calculator; the addition is subsequently performed and the result printed.

“−f…“  is a formatting statement; 2f8.1 follows the fortran convention for formatting real numbers.

Example 2.2   Standard input and standard output

After all the command-line arguments are parsed, usually mcx prints the top-level array s0, and exits silently.
However,

  • If s0 is not present, mcx waits for you to enter an array from standard input.
    For example try

    $ mcx -f2f8.1
    $ 1 2
    $ 3
    $ 4 <ctrl-D>
    

    mcx should print out

    % rows 2 cols 2 real
         1.0     2.0
         3.0     4.0
    
  • If the last command is −show, mcx just prints out information about named arrays and the stack and exits (even if the stack has no arrays). Thus the command
    mcx -f2f8.1 mat1 mat2 -show -+ -show
    does the same as it did in Example 2.1 but prints out stack contents a second time, instead of printing s0.

You can also tell mcx to read the next array from standard input by using a full stop (“ . “) in lieu of file name. Thus
echo 1 -2 3 -4 | mcx .
pushes a 1×4 array onto s0, while
echo 1 -2 3 -4 | mcx -nc=2 . mat2 -+
pushes a 2×2 array onto s0, then pushes mat2, and adds the two so that a single array remains on the stack. −nc=2 tells mcx to treat the line from stdin as an array with 2 columns.

Example 2.3   Manipulations of eigenvalues and eigenvectors of an array

This example finds the eigenvalues e and eigenvectors z of mat2, and shows that mat2 z = z e.

First try
mcx mat2 -evl
You should see a 2×1 complex array

% rows 2 cols 1 complex
   -0.152067
   13.152067

    0.000000
    0.000000

The eigenvalues are complex because the matrix is not hermitian. The imaginary part follows the real part; this is how mcx displays and reads complex arrays in ASCII format.

You can force mat2 to be hermitian (symmetric since mat2 is real) with −herm. Now do
mcx mat2 -herm -a h h -evl h -evc -ap z -tog -v2dia -x h z -x --

These instructions do the following:

  • mat2 : reads file mat2 and pushes it onto s0.

  • −herm : symmetrizes s0.

  • −a h : copies s0 to a named array  h  and pops it from the stack. The stack is now empty.

  • h −evl : pushes h onto s0 and replaces s0 with its eigenvalues. Because h is hermitian, s0 is real.

  • h −evc : pushes h onto the stack and replaces s0 with its eigenvectors. Now the stack has two arrays, s0 = z and s1 = e.

  • −ap z : copies s0 to a named array  z.

  • −tog : toggles s0 and s1, making s1 = z and s0 = e.

  • −v2dia : Turns s0 (a vector or 2×1 array of eigenvalues) into a diagonal 2×2 array.

  • −x : multiplies s1 × s0. One array remains on the stack, s0 = z × e.

  • h z −x : pushes h and z onto the stack and multiplies them. Now s0 = h × z, while s1 = z × e

  • −− : Adds s1 to −s0.  s1 and s1 are mathematically identical so the difference should be zero.

Note: this formula should still work even if h is not hermitian.

See Instruction Summary

Example 2.4   Numerical integration, differentiation, and interpolation of a function

Integrate and differentiate the function , by tabulating it on a mesh and evaluating integrals and derivatives numerically. This example also uses the tabulated data to interpolate it to another mesh.

Copy the contents of the box below into file dat.

% const n=100 p=1 lam=2
% save
% macro iy(z) exp(-lam*z)*(-lam*z-1)/lam^2
% repeat i= 0:n
% var x=10*i/n
{x} {x^p*exp(-lam*x)}
% end

This creates 101 rows of xy pairs with x ranging between 0 and 10.

Note: : The number of points n+1, and also p and λ are declared in the file with the const preprocessor directive. You can override the values assigned there with command-line arguments, e.g. −vp=#. The save directive retains the variables declared in this file after it is read. The macro directive will be used for the indefinite integral, below.

Note: : A macro can also be specified on the command line, e.g. ‘-miy(z)=exp(-lamz)(-lam*z-1)/lam^2’

Derivative

The derivative is readily found to be

Try some of the following commands

$ mcx -vp=2 dat -diff
$ mcx -vp=2 dat -diff -e3 x1 x2 'x1^(p-1)*(p-lam*x1)*exp(-lam*x1)'
$ mcx -vp=2 -f3f15.10 dat -diff:nord=5 -e3 x1 x2 'x1^(p-1)*(p-lam*x1)*exp(-lam*x1)' -e3 x1 x2 x2-x3

All of them differentiate the second column with respect to the first, using p=2.

  • The first returns two columns with x and y′.
  • The second returns three columns with x, y′, and the analytic derivative of y′.
  • The third returns three columns (more decimals) with x, y′, and the error in the numerical estimate for y′.

Unpacking the third command:

ArgumentFunction
−vp=2Declares variable p and assigns the value 2. This overrides the assignment in dat.
−f3f15.10Formats output (fortran format 3f15.10)
datread s0 from dat.
−diff:nord=5Replace column 2 with a numerical estimate for y
Use a 5-point polynomial to interpolate the data; estimate is derivative of polynomial interpolation
−e3   x1   x2   ‘x1^(p−1)*(p−lam*x1)*exp(−lam*x1)’replace s0 with a three column array consisting of x, y′, and the analytic derivative of y
−e3   x1   x2   x2−x3replace s0 with a three column array consisting of x, y′, and difference between the numerical and analytical y

Some observations:

  • The largest error appears for x→0. The interpolation is less accurate when all the data lies on one side of the interpolating point.
  • The error improves when higher order polynomials (nord=#) are used, or when the mesh is made finer (−vn=#).
  • If you use p<1, y′ diverges at the origin. The numerical derivative cannot reproduce this.
Integral

y is small at x=10 if λ=−2, provided p is 3 or less; so we will use 10 in place of ∞.

Try some of the following commands

$ mcx -vp=1 dat -int 0 10
$ mcx -vp=2 dat -int 0 10
$ mcx -vp=3 dat -int 0 10

These commands calculate  I  between 0 and 10 for three values of  p.

You should find that  I  is close to , i.e. 1/4, 1/4, and 3/8 for p=1,2,3. Some numerical errors appear in the 6th digit. The integral is carried out by fitting the data to a polynomial of order nord−1, and integrating the polynomial. You can reduce the error by using a higher order than the default value of 4 for nord, viz

$ mcx -vp=3 dat -int:nord=6 0 10

Also for p>3 you should increase the upper bound beyond 10 since the integral from 10 to ∞ is on the order of 10−6.

Indefinite Integral

As noted  I  must be evaluated between definite limits. However, you can make mcx simulate an indefinite integral by integrating over a range of upper bounds.

To compare with exact results, note that when p=1 the indefinite integral is

The macro in dat evaluates this integral.

Try the following:

$ mcx dat -int 0 0:2:.2 -e3 x1 x2 'iy(x1)-iy(0)'

This evaluates  I  for a lower bound of 0 and a uniform mesh of points for the upper bound between 0 and 2. In the third column the analytic integral is evaluated from the macro iy at the upper and lower bounds.

You should that the numerical and analytic integrals agree to about 6 decimal places:

% rows 11 cols 3 real
    0.000000    0.000000    0.000000
    0.200000    0.015387    0.015388
    0.400000    0.047801    0.047802
    0.600000    0.084343    0.084343
    0.800000    0.118767    0.118767
    1.000000    0.148498    0.148499
    1.200000    0.172890    0.172890
    1.400000    0.192230    0.192230
    1.600000    0.207200    0.207200
    1.800000    0.218578    0.218578
    2.000000    0.227105    0.227105

Alternatively, you specify macro on the command line and omit it from the dat file

$ mcx '-miy(z)=exp(-lam*z)*(-lam*z-1)/lam^2' dat -int 0 0:2:.2 -e3 x1 x2 'iy(x1)-iy(0)'
Interpolation

Interpolation proceeds much in the same was as integration; only interpolation has lower bound. Try

$ mcx -vp=2  dat -intrp .5:1:.05 -e3 x1 x2 'x1^p*exp(-lam*x1)' -e3 x1 x2 x2-x3

This returns the abscissa on a mesh twice finer than the original mesh. Every odd point is perfectly interpolated (they lie on the original mesh); the even points reflect the error of the interpolation.

See Instruction Summary.

Example 2.5   Convert a k-point given in Cartesian coordinates to multiples of the reciprocal lattice vectors

Often it is necessary to convert a k point given in Cartesian coordinates a vector expressed as multiples of the reciprocal lattice vectors, or vice-versa. This example provides a simple recipe for the conversion using mcx.

The valence band maximum of an insulator was found to occur at q=(0.702085,0.711920,0.231304) in Cartesian coordinates, in units of 2π/a, where a is the lattice constant.

The real and reciprocal space lattice vectors are

                Plat                                  Qlat
   1.070990   0.000000  -0.685190        0.933715   0.000000   0.000000
   0.000000   1.000000   0.000000        0.000000   1.000000   0.000000
   0.000000   0.000000   1.189949        0.537647   0.000000   0.840372

Let and be the same point expressed as multiples of Cartesian vectors (, , ) and reciprocal lattice vectors Q. In the snippet above (taken from lmf standard output) row i corresponds to the ith lattice vector Pi or Qi. Thus element in the 3×3 matrix shown for Q corresponds to Cartesian component j of Qi. Call this ; note that it is the transpose of the matrix in the snippet. Note also, according to standard definitions, .

By definition,

Writing as a row vector ,

To obtain using mcx, invoke

mcx '-array[3,3]' 1.070990,0,-0.685190,0,1,0,0,0,1.189949 -a plat '-array[1,3]' 0.702085,0.711920,0.231304 plat -x

It should yield 0.593439 0.711920 0.275240.

Example 2.6   Rotation matrices

mcx can generate rotation matrices, for example:

mcx -rot='(0,0,1)pi/2'

generates the following 3×3 matrix:

    0.000000    1.000000    0.000000
   -1.000000    0.000000    0.000000
    0.000000    0.000000    1.000000

Operating on a column vector, it maps into , into , and into itself.

Thus rotations are defined in the following sense: for a right-handed coordinate system (meaning positive rotation around is counterclockwise) You can think of it either :

  • An “intrinsic” or “passive” convention where the coordinate system is rotated instead of space, in the opposite direction. In the above example, the coordinate system rotates clockwise for positive angle π/2.
  • An “extrinsic” or “active” convention where space rotated. In the above example, are rotated counterclockwise to .

-rot can accept a sequence of rotations. For example, Euler angles are a specification of three rotations: first about by , then about the new by , finally about the new by . To generate the rotation matrix for Euler angles , , , do:

mcx -rot='(0,0,1)pi/4,(0,1,0)pi/3,(0,0,1)pi/2   or
mcx -rot=z:pi/4,y:pi/3,z:pi/2

To confirm that this operation is a compound of the three rotations, make them separately and multiply them out:

mcx -rot='z:pi/4' -a r1 -rot='y:pi/3' -a r2 -rot='z:pi/2' -a r3  r3 r2 r1 -x -x

mcx can also generate the rotation matrix rotating real harmonics to spherical harmonics and vice-versa.

mcx -f18f12.6 -ylm~r2s~l=2

It can also rotate from real or spherical harmonics to the relativistic basis by quantum numbers , (or , ).

mcx -f18f12.6 -ylm~r2kmu~l=2

3. mcx manual

mcx is a stack-based, command-line driven calculator for matrices. Matrices reside on the stack, ordered as s0, s1, … . There are unary operators that operate on the top-level element s0, replacing it with some transformation, and binary operators that operate on s1 and s0 replacing both of them with the result of some operation, e.g. s1 × s0.

Usage:

mcx [−switches] data-file -ops …

Arguments that do not begin with  “−“  or  ”[“  must be files, stored in the form of a 2D array. For ASCII files, data is read using the standard Questaal format which features programming language capabilities.

Any argument that begins with  “−“  is a switch, a unary operator, or a binary operator.

Any argument that begins with  ”[“  is a declaration of a command-line looping construct where command arguments between  ”[“  and  ”]”  are iterated over, as described below.

When a file is read, its contents (together with the number of rows nr and columns nc) is pushed onto the stack and becomes the top-level stack element s0. Elements already existing on the stack get pushed down one level. If there are n such elements, si-1si for i = n, n−1, …, and the new element becomes s0.

Data is normally read from a file; however if data-file is a full stop (“ . ”), data is read from standard input in lieu of a file. (It can occur only once). See Example 2.2.

Switches

These are switches that modify variables and describe or control formatting of data files that are read and written.

  • −nc=# (nr=#)
    Stipulate that next matrix read has # columns (rows). See Example 2.2 for an illustration.
  • −vvar=#
    create variable var if it does not already exist, and assign value to  #. This is the standard way Questaal programs assign variables from the command line. Since data files are parsed by the preprocessor, such variables may enter into preprocessor directives or as part of expressions in the data itself.
  • −show
    show data stack and any operations pending. See Example 2.1.
  • −mmymacro</FONT>(arg1,arg2,...)=expr</FONT></i>(arg1,arg2,...)\\ Creates a macro that is parsed in the same way as explained in the documentation for [macro preprocessor directives](/docs/input/preprocessor/#macro-directive). (You can also include macros as preprocessor directives in data files, as was done in [Example 2.4](#example-24--numerical-integration-differentiation-and-interpolation-of-a-function).\\ _Example:_{: style="color: coral"} macro max takes the maximum value of two numbers: `'-mmax(x1,x2)=x1>x2?x1:x2'` .
  • −w[:switches] fname  |  −bw[:switches] fname
    write s0 to file fname.
    −bw writes to a binary file.
    Optional switches are separated by whatever character follows −w (assumed to be  ’:’ here).
    • :l=label    include a label in the header
    • :nohead   Suppress writing the header line
  • −wap
    (complex arrays only) write s0 as (amplitude,phase) rather than (Re, Im).
  • −a[nr=#|:nc=#] nam | −ap nam
    assign s0 to nam, and pop s0 off the stack. −ap nam performs the assignment but does not pop s0 off the stack.
  • −av[ir,ic] var
    assigns scalar variable var to element from s0(ir,ic). If ir and ic are specified, the (1,1) element is used.
  • −r:tags
    tags are separated by whatever character follows −r (assumed to be  ’:’ here). Tags are:

    :qrread with fortran read (fast, no algebra)
    :s=#skips # records before reading
    :openleaves file open after reading; thus if you read the file again it will read the next array
    :br[nr,nc]read from binary file. If not specified read nr and nc from first record.
    :h5~switchesread a dataset from a file in hdf5 format, which must be an array of n dimensions. One or two of the n are selected out.
    Switches are separated by the character after h5 (assumed to be  ’~’ here).
    The following switches are required:
     ~id=name   dataset name. Number of columns and dimension for each are read from the file.
     ~c=#1,#2,… read #1,#2,… elements from columns 1,2,… of the dataset. # unspecifed or 0 ⇒ file dimension. Only 2 elements may exceed 1.
    The following switches are optional:
    ~check    print properties of dataset, without reading contents
    ~i       indicate that the dataset consists of an integer array
    ~z      indicate that the dataset consists of a complex array
    ~o=#1,#2,… offsets to columns 1,2,… of the dataset. Unspecified elements default to 0
     ~s=#1,#2,… (stride) spacing between elements in columns 1,2,… of the dataset. Unspecified elements default to 1
    Example: print elements (1:20,68,1:2,20) of dataset cphi in files cphi.h5. cphi is a complex array dimensioned (205,72,2,22).
    Note offsets start at 0 and the use of 0 in ~c=.
     mcx -r:h5~z~id=cphi~o=0,67,0,19~c=20,1,0,1 cphi.h5
    :spcload in sparse format
  • −px[:nprec]
    write in row (column) compressed storage format, displaying only elements larger than a tolerance By default the tolerance is 10−8. If nprec is supplied, the tolerance is 10−nprec.
  • −pxc
    Not documented.

See Instruction Summary.

Unary operators

These operators act on the top level matrix, s0, and replace it with the result of the unop.

Where expr appears in the switches below, algebraic variables declared from directives may be used; also you can use xn for the contents of the nth column.

  • −p:
    Pushes top array s0 onto stack, duplicating it.
  • −p+n (-p-n):
    Pushes nth array (from bottom) onto stack
  • −pop:
    Pops s0 from stack, shifting the other elements up one level.
  • −popu:
    Pop a unary operator from the stack, if present
  • −popb:
    Pop a binary operator from the stack, if present
  • −csum[:list]
    Sums the columns of s0, replacing it with a matrix of one column.
  • −rsum[:list]
    Sums the rows of s0, replacing it with a matrix of one row.
  • −s#:
    Scale s0 by # (may use -s#real,#imag)
  • −shft=#:
    Adds a constant # to s0
  • −sort expr
    Sorts rows s0, ordering them by the result of expr
  • −i | − iq:
    Inverts s0
  • −1:n
    Pushes unit matrix, dimension n, onto stack
  • −evl | −evc
    Replaces s0 by its eigenvalues (eigenvectors)
  • −t:
    Transposes s0
  • −cc:
    Take complex conjugate of s0
  • −herm: Replaces s0 with its hermitian part
  • −real:
    Replaces s0 with its real part
  • −v2dia:
    If s0 is a vector, it is expanded into diagonal matrix.
    If s0 is a square matrix, its diagonal elements are used to form a vector.
  • −split   nam   row-markers   column-markers
    Splits s0 into subblocks. row-markers and column-markers. Both markers consist of standard Questaal integer lists, and delineate the first row (column) of a subblock, and also implicitly delineate the last row (column) of the prior subblock. Thus 1,6,20 comprises two subblocks, the first with range [1,5], the other with range [6,19].
    For each i and j, where i and j are the ith and jth subblock, a permanent array called namij will be created. Thus -split creates n1×n2 new named arrays, with n1 and n2 being the number of row and column subblocks.
    Example: suppose myfile contains 27 rows and 4 columns. Then
    mcx myfile -sub 1,27,1,4 -split x 1:nr+1:9 1,2,nc+1 -show
    creates 6 new arrays named x11, x12, x21, x22, x31, x32. All have 9 rows; x11, x21, x31 have one column while x12, x22, x32 have three columns.
    Note 1: You can use nr and nc to refer the number of rows and columns, respectively.
    Note 2: You can use . in lieu of an integer list for either row-markers or column-markers. It is equivalent to the list 1,nr+1 for the rows and 1,nc+1 for the columns.
  • −rep:n1,n2
    Concatenates replicas of s0 to create (nr×n1,nc×n2) array.
  • −roll:#1[,#2]
    Cyclically shifts rows (and columns, respectively) by #1 (and #2) elements.
  • −pwr=#:
    Raises (col-1) matrix to a power
  • −wl expr
    For each row in the top-level array, evaluate expr and return 1 if nonzero, or 0 if zero. If nr is the number of rows, nr numbers will be returned in a single column.
    Example:
    mcx '-array[4,2]' -6.2625636,-6.2605747,-6.2625635,-6.2605746,1,2,1,3 -t -wl 'abs(x1-x3)+abs(x2-x4)>1d-6'
    returns two lines : 0 in the first line and 1 on the second.
  • −tp [nc~]list
    Generates matrix from list. Elements in list is a sequence of real numbers, in the form of standard Questaal syntax for integer lists.
  • −rot=strn
    Create a 3×3 rotation matrix defined by elementary rotations in strn.
    strn should take the standard Questaal syntax for rotations constructed from a product of elementary rotations about specified angles.
  • −roteu
    Converts a rotation matrix resident on the stack to Euler angles (an inverse operation to −rot=). Examples:
    mcx -rot=x:pi/2 pushes a new 3x3 array (rotation) on the stack while
    mcx -rot=x:pi/2 -roteu returns the Euler angles for that rotation

  • −ylm~l=l [~switches]
    A multifunction rotator of spherical harmonics.
    you must specify a value l which, depending on the mode specifies a particular l block of real or spherical harmonics Ylm.

    Default mode
    returns a square array of rank (l+1)2, a matrix R that rotates a a linear combination of Ylm in one reference frame to the corresponding combination in a rotated reference frame. If the linear combination is specified by column vector C, The corresponding combination in the rotated frame is R C.
    No special switches are required but a 3×3 rotation matrix must be on the top level of the stack (you can make one with −rot=strn).
    Example:  : a π/2 rotation around z rotates (x,y) into (−y,x) (clockwise active rotation of vectors; or anticlockwise passive rotation of coordinates).
    The l=2, m=−2, and l=2, m=2 orbitals, which are xy and x2-y2, are mapped into their negatives, −xy and y2x2.
    The l=2, m=−1 orbital (yz) is mapped to −xz; the l=2, m=+1 orbital (xz) is mapped to yz.
    the l=2, m=0  orbital (3z2−1) is mapped to itself.
        mcx -f9f12.6 -rot=z:pi/2 -p -ylm~l=2 -sub 5,9,5,9
    Optional switches available in this mode:
    ~spin creates a 2×2 superarray with the (1:2,1:2) subblocks corresponding to spins ±1/2. each subblock of the superarray is a diagonal, constant matrix of rank (l+1)2. The orbital part is not rotated.
    ~spin+o Combines spin and orbital rotations. The superarry is a product of the spinor and orbital rotations.
    ~spin+only Also creates a 2×2 superarray, but only orbital part is rotated.
    ~sh works with true spherical harmonics instead of real ones.
    ~sh2 Same, but m is ordered l, l−1, …, −l (reversed from the normal ordering).
    mode ~v=x,y,z
    Evaluates the real form of the spherical harmonics polynomial at a point  x,y,z; see this page.
    modes ~s2r and ~r2s, and ~s2rl and ~r2sl
    ~r2s pushes onto the stack the complex conjugate u* of matrix u defined by Eq. (9) in the spherical harmonics documentation.
    u* is a square array of rank (l+1)2 that rotates a linear combination of real harmonics , to the corresponding combination of true spherical harmonics .
    If C is a vector representing a linear combination of ,  u*C is the corresponding linear combination of .
    You must specify a particular l (use ~l=#). No arrays are needed from the stack.
    s2r and s2rl are the same (as are r2s, and r2sl) except that the former prints out the matrix for all l up to the specified one, while the latter prints the matrix for one particular l.
    • s2r, s2rl matrix to rotate spherical to real harmonics, i.e. generate (u*)−1 = uT
    • r2s, r2sl matrix to rotate real to spherical harmonics, i.e. generate u*
      Example:  : rotate l=2 spherical harmonics into real harmonics.
            and   .
      These 2×2 matrices can be extracted from (1,5) and (2,4) columns of the 5×5 rotation matrix generated by -ylm~s2rl~l=2:
          mcx -ylm~s2rl~l=2 -coll 1,5 -rowl 1,5
          mcx -ylm~s2rl~l=2 -coll 2,4 -rowl 2,4
    modes ~r2kmu and ~s2kmu, and ~kmu2r and ~kmu2s
    pushes onto the stack the matrix rotating either real to spherical harmonics to relativistic angular momenta given by quantum numbers , . The latter two forms are the inverse operations.
    ~rots mode
    rotates a square structure matrix Smm′ which represents an expansion in bilinear spherical harmonics   |Ylm(1)> Smm′  <Ylm′ (2)|. S is rotated to R S R−1.
    In this mode S must be the top-level array on the stack. Additionally you must specify a rotation matrix. There are three options:
    • ~eula=#,#,# The three Euler angles α, β, γ that define a rotation matrix
    • ~rot=strn A string defining a rotation (same syntax ax −rot=strn above)
    • ~ntry=# makes a stochastic search for a rotation that minimizes the off-diagonal part of S
  • −array[#1,#2]   #,#,#,…
    Push onto the stack a new real array of dimension (#1,#2). The second argument must consist of #1×#2 expressions separated by commas. They specify elements
    (1,1), (1,2), … (1,#2), (2,1), (1,2), … (1,#2), … (#1,1), (#1,2), … (#1,#2) .
    Example:mcx -f18f8.2 -array[2,3] 6,5,4,3,2,1   creates a 2×3 array with the second row containing elements 3,2,1, respectively.
  • −sarray[#1,#2]   |   −sarrayr[#1,#2]   |   −sarrayc[#1,#2]   |   −sarrayz[#1,#2]  
    Assemble a superarray of #1×#2 arrays pre-existing on the stack. It is an error these stack arrays are not present.
    • −sarray[#1,#2]  : The top rows of the superarray are constructed from the first #2 arrays on the stack; The bottom rows from the last #2 arrays.
    • −sarrayz[#1,#2] : reverses stack order, so the (1,1) and (#1,#2) elements of the superarray are copied respectively from from s#1×#2 and s0.
    • −sarrayc[#1,#2] : reverses column order but not row order of stack.
    • −sarrayr[#1,#2] : reverses row order but not column order of stack.

    Constituents of each superblock row (e.g. the first row, s0,   s1, …,   s#2−1) must have a fixed number of rows. Also each superblock row must combine to make the same number of columns.
    See below for an example.

See Instruction Summary.

Row and column Unary Operators

These unops treat s0 as an array of nr rows and nc columns.

  • −rowl list  |  −coll list
    Creates a new array from a list of rows (columns) of s0
  • −rowl:mirr  |  −coll:mirr
    Rearranges rows (columns) in reverse order
  • −rowl:pf=fnam  |  −coll:pf=fnam  |  −rowl:ipf=fnam  |  −coll:ipf=fnam
    Same as −rowl (−coll) but list is read from permutation file fnam. ipf reverses the sense of the permutation.
    Example: file perm contains 2 3 1 4. Then
    • −rowl:pf=perm returns s0 with rows 2,3,1,4 permuted into 1,2,3,4
    • −rowl:ipf=perm returns s0 w/ rows 3,1,2,4 permuted into 1,2,3,4
  • −inc expr
    Retains rows from s0 for which expr is nonzero.
  • −sub t,b,l,r  |  -sub t,l
    Extracts a subblock of s0. In second form, bottom right corner = (nr,nc).
  • −subs:# t,b,l,r
    Scales a subblock of s0 by #.
  • −subv:# t,b,l,r
    Copies # to subblock of s0.
  • −e# expr1   expr2   …   expr#
    Create new matrix of # columns with values expr1   expr2   … expr#  .
    Variables x1,   x2,   … can be used in the expressions. These variables refer to the elements of s0in columns 1, 2, …, and change with each row.
    This switch is used in Example 2.4.
    Note: : at present this switch does not work for complex arrays.
  • −abs
    takes the absolute value of each element
  • −max[:i|g]
    puts the largest element in a given row into the first column.
    Optional g returns max value of the entire array
    Optional i returns index to max value.
  • −nint[#1]
    Replaces each element with nearest integer.
    Optional #1: scale array by #1 before operation, and by 1/#1 after. Thus -nint:1000 rounds to nearest thousandth.

See Instruction Summary.

Unary Operators that treat data as discretized continuous functions of the first column

In these unops, column 1 (x1) is treated as an the independent variable.

Three of these unops fit data in other columns with a polynomial in x1. The polynomial is used to differentiate (−diff), integrate (−int), or interpolate (−intrp) data in the remaining columns. There are some modifiers (called [:opts] in the documentation below):

  1. :nord=# will change the number of points in fitting polynomial to  # (polynomial order is #−1). The default value is #=4.
  2. :rat will use a rational polynomial, rather than an ordinary one. Good for data with singularities.
  3. :mesh (applies to −int only) replaces s0 with its integral on the same mesh as the original set of values x1. A trapezoidal rule is used at present.

You can string the options together. These three unops are demonstrated in Example 2.4.

  • −diff[:opts]
    differentiates columns 2…nc using column 1 as the abscissa s0 is returned as a table of points with list in the first column and the remaining columns replacing the function value at each x1 with its (numeric) derivative.
  • −int[:opts] xlo list
    integrates columns 2…nc using column 1 as the abscissa, from the lower bound xlo to a set of upper bounds, given by list.
    s0 is returned as a table of points with list in the first column and the result of the integral in the remaining columns.
  • −intrp[:opts] list
    interpolates column 2 to points in list, using column 1 as the abscissa.
    s0 is returned as a table of points with list in the first column and the result of the interpolation in the remaining columns.
  • −smo width,xmin,xmax,dx:
    smooths vector of delta-functions with gaussians
  • −unx[:i1] #1,#2
    (uncross) exchanges points in columns #1 and #2 after their point of closest approach
  • −unx2[:i1] #1,#2
    (cross) exchanges points in columns #1 and #2 at their point of closest approach, if they do not cross.
  • −at[:i1] val expr
    find adjacent rows that bracket expr=val. Array contains linearly interpolated x1 and expr.
  • −ipoly=x
    Constructs a Lagrange interpolating polynomial from points in column 1. s0 must be an array with one column; the order of polynomial is the number of points. This switch returns weights to use at the given points in order to interpolate some object (e.g. a function or matrix) known at the given points to point x.
    Example:mc '-array[3,1]' 1/2,0,1 -ipoly=1/4 -t
    returns a three-element vector, 3/4, 3/8, -1/8. Applying these weights to a linear combination of some object known at points 1/2, 0, 1, will estimate the object at x=1/4, using a quadratic interpolation. Note that the sum of the weights must be unity.

See Instruction Summary.

Find numerical differences read from a pair of files with mixed text and numbers

mcx has a special mode, which you invoke with the command-line argument -cmpf. It does not act on the stack but instead reads two files, comparing line by line, extracting words (i.e. strings separated by spaces) that appear to be floating point numbers, and numerically evaluating their difference.

Its default operation is to print out information about the file, such as:
lines 1:29 cols 1:75 words 152 chars 1214 ndiff 3 max 10

You can print print out a subset of this information (see printopt below). This is intended for scripts that compare differences in the numerical values in two files.

Blank lines in either file are skipped over. There is no facility, such as with the diff command, to re-align lines where extra lines are present in only one file.
The syntax for this switch is:

-cmpf[~ln=..][~col=..][~sep=<i>c</i>][~quiet][~verb][~long][~char|~tol=#][~rnge=#1,#2][~incl=<i>s</i>][~excl=<i>s</i>][~term=<i>c</i>][<i>printopt</i>]~fn1=<i>f1</i>~fn2=<i>f2</i>|~diffy=#

The first character following -cmpf is the delimiter separating tags (assumed here to be ~). ~fn1 and ~fn2 are required; the rest are optional. (Alternatively, ~diffy may substitute for ~fn2.)

Their meaning is:

  • ~ln=#[,#2]
    Compare only the first # lines, or if #2 is present, lines in the range (#,#2).
    If #2 is present with value zero, lines #…END are compared
  • ~col=#[,#2]
    Compare only the first # columns, or if #2 is present, columns in the range (#,#2)
  • ~sep=c
    If a word contains character c, it is split into separate words using c as the delimiter.
    Thus if c is “=”, the word DQ=1e-6 is split into two words, the second being a number.
    Note that c can be a sequence of characters.
  • ~quiet
    silent mode : prints out nothing but returns the number of differences to stdout (capped at 255)
  • ~verb |  ~vverb
    verbose mode: prints out information about each line. The latter is a very verbose mode: it also prints out the lines themselves.
  • ~long
    compares longest of the two lines. The shorter line is filled with blanks. By default, lines are compared only up to the smaller number of words in the two lines.
  • ~char
    a special mode that does no numerical conversions, but compares lines character by character
  • ~tol=#
    If the difference in numerical values of words converted into numbers is less than  #, the two are treated as equal.
  • ~rnge=#1,#2
    If a number extracted from either f1 or f2 lies outside the range (#1,#2), no comparison is made.
  • ~excl=s
    Tells mcx to exclude lines containing character string s. If ~excl appears more than once, mcx will exclude lines containing any of the associated strings.
  • ~incl=s
    Tells mcx to compare only lines containing character string s. If ~incl appears more than once, mcx will include lines containing any of the associated strings.
  • ~term=c
    When a character c is encountered in either file, mcx terminates the comparison .
    Note that c can be a sequence of characters.
  • printopt   is one of the keywords below. Its function is to change mcx output write a single number. printopt should be one of:
    • ~nchar returns the total number of characters in the rows and columns read.
    • ~nword returns the number of words
    • ~ndiff returns the number of instances of numerical words found to be different, or if ~char is present, the number of differences in characters
    • ~max returns the global maximum numerical difference encountered
  • ~fn1=f1
    f1 is the first file to be compared.
  • ~fn2=f2
    f2 is the second file to be compared.
  • ~diffy=#
    This may be used as an alternative to ~fn2=f2. Then f1 must contain side-by-side differences of two files generated by the unix diff command. To create f1, run diff on the two files to compare (call them filea and fileb as follows:
    diff -W # [--suppress-common-lines] -y filea fileb | expand > f1
    Note that # is the width of the combined file. Use the same value when running mcx as mcx -cmpf~fn1=f1~diffy=#...

Example: Compare how –help differs between lm and lmf. Assuming lm, lmf, and mcx are in your path, do :

lm --help > file1
lmf --help > file2
mcx -cmpf~fn1=file1~fn2=file2~col=40~vverb

You should see the first 40 columns of the two outputs displayed line by line, a summary of the differences found for each line pair, and at the end a summary similar to:

 lines 1:29  cols 1:40  words 99  chars 814  ndiff 3  max 10

Binary Operators

These operate on the top two matrices in the stack, s1 and s0. s1 and s0 are popped from the stack, and the result of the binary operation is put into s0.

Dimensions for s0 and s1 are not independent; for example if they are added they must have the same number of rows and columns.

  • −tog
    Toggle s0 and s1.
  • −+
    Add s1 + s0
  • −−
    Add s1s0
  • −x
    Multiply s1 × s0
  • −xe
    Multiply s1 and s0 element by element
  • −de
    Divide s1 / s0 element by element
  • −x3
    Multiply s1 s0 are thou they are 3D arrays: s1 = s1(n11,n21,n31) s0 = s0(n10,n20,n30) where n10=nr(0)/n20,n20=nc(1),n30=nc(0); n11=n10,n21=nr(1)/n11,n31=n20 Result(i,j,k) = sum_m s1(i,j,m) s0(i,m,k) is condensed into 2D (nr(1),nc(0))
  • −gevl  |  −gevc
    Same as −evl  |  −evc, but for the generalized eigenvalue problem. s1 is the nonorthogonal matrix.
  • −orthos:
    Replace s0 with s1-1/2 s0 s1-1/2
  • −ccat:
    Concatenate columns of s1 and s0 into a single array
  • −rcat:
    Concatenate rows of s1 and s0 into a single array
  • −cross:
    Cross product s1(1,1..3) x s0(:,1..3)
  • −suba[#] t,b,l,r  |  -suba[#] t,l
    Copy s1 to subblock of s0. Conventions for subblock are the same as for −suba t,b,l,r  |  -sub t,l.
    Optional # copies #×s1 into s0.
  • −index:
    Use s0 as an row index to s1. s0(i) is overwritten by s1(s0(i)). s1 is preserved. New s0 has row dimensions of the original s0 and column dimensions of s1.

See Instruction Summary

Repeated Iteration of Command Line Arguments

Command line arguments can be repeated by enclosing them in brackets, with the syntax

[ name=list arg1 arg2 arg3 ... argn ]

list is a standard Questaal integer list.

mcx executes the sequence of command line arguments arg1, arg2, arg3, …, argn for each element in list. Within this special construct, arg1, arg2, … are treated as strings that are parsed for expression substitution. In particular, variables name and i are loaded and recalculated each pass. name is the value of the current integer, and i is the index in the list.

name= is not required; mcx will use ir as the loop variable if it is omitted.

The scheme is best explained by a concrete illustratation.

Example 1:

Suppose files   a0, a1 and a4   reside on disk, with a0 a 4×4 symmetrix matrix, a1 4×4 hermitian, and a4 1×3 real. The command

mcx [ k=0,1,4 'a{k}' ] -show

should get expanded to a sequence of four arguments

 loopcounter ikargumentaction
110a{k}a0 loaded onto stack
221a{k}a1 loaded onto stack
334a{k}a4 loaded onto stack
4---showdisplays stack

Note tha both loop counter i and loop variable k are remade each iteration.

You should see the following:

# 0 named arrays, 3 on stack; pending 0 unops 0 bops (vsn 1.058)
# stack             nr    nc   cast
#    3               1     3   real
#    2               4     4   herm
#    1               4     4   symm
Conditional evaluation of an argument

Within the  [ … ]  construct, an argument that begins with  ?  is treated as an expression. The result of that expression determines whether the subsequent argument should be evaluated or skipped. Thus the construct

mcx ... [ ... '?expr' argi ... ]

parses expr as an expression. If it evaluates nonzero, argi is executed. Otherwise, argi is passed over.

Example 2:

mcx [ 0:2 'a{ir}' '?i>1' -rcat ]
  • Pushes a0 on the stack (note that variable ir is used as default, since no name wsa spcified)

  • Evaluates expression ?i>1. In the first pass the loop counter is 1, so the expression evaluates to false and the next argument is ignored.

  • Pushes a1 on the stack

  • Evaluates expression ?i>1, which now evaluates to true. The -rcat argument is parsed, row-concatenating a0 and a1 leaving a single array on the stack

  • Pushes a2 on the stack, can row-concatenates it to the existing stack

The final stack consists of a single array which concatenates a0, … , a2.

Special handling of the last iteration

You can prevent the last argument (or arguments) in the loop from executing, by appending a  /  to the   [. A single slash suppresses the last argument, two slashes suppress the last two arguments, and so on.

Example 3: cut and paste the 2×2 matrix in the box below to file a.

1 x
x x*x

Then do:

mcx  [/ 1:3 '-vx={i}' a -+ ]

This sums three instances of  a  with x=1, x=2, and x=3. Note that three arrays are loaded but there are only two additions, so   −+   should be suppressed the last iteration.

You should see the following output:

% rows 2 cols 2 real
    3.000000    6.000000
    6.000000   14.000000

The (1,1) element is the sum of x0 for x=1…3, while (1,2) and (2,1) are the sum of x1 and (2,2) is the sum of x2.

To see the arguments being parsed in detail, use the -debug switch:

mcx -debug [/ 1:3 '-vx={i}' a -+ ]
Nested iterations of commands

The looping construct can be nested, as illustrated by the following example. It makes a 6×6 array from assembling 9 instances (3 rows and three columns) of a single 2×2 array, modifying each instance.

Example 4:

Use nested loops to make the following array

% rows 6 cols 6 real
   14.00   12.00    0.00    0.00    0.00    0.00
   13.00   11.00    0.00    0.00    0.00    0.00
    0.00    0.00   24.00   22.00    0.00    0.00
    0.00    0.00   23.00   21.00    0.00    0.00
    0.00    0.00    0.00    0.00   34.00   32.00
    0.00    0.00    0.00    0.00   33.00   31.00

The three diagonal 2×2 blocks are the array [[4,3],[2,1]], shifted respectively by 10, 20, 30. The following command makes this array:

mcx -f18f8.2 [ ix=1:3 [ jx=1:3 '-array[2,2]' 4,3,2,1 "-shft=jx*10" '?jx<>ix' -s0 ] ] '-sarray[3,3]'

Compare what happens when you load elements in reverse order, e.g. with -sarrayz[3,3], -sarrayr[3,3], -sarrayc[3,3].

Example 5: Given a pair of 32×32 arrays in files A and B, split each into four 16×16 subblocks, and create an interleaved 64×64 array of the form

In the following command, -1:16 -s0 -a z creates a 16×16 array of zero value, named z. The two -split commands create four subblocks each of arrays a and b. Finally the 16 subblocks are pushed onto the stack in the order as they occur in the array, and assembled with -sarray[4,4].

mcx -f16f12.6 -1:16 -s0 -a z A -split a 1:nr+1:16 1:nc+1:16 -pop B -split b 1:nr+1:16 1:nc+1:16 -pop \
    a11 z a12 z z b11 z b12 a21 z a22 z z b21 z b22 '-sarray[4,4]'

Return to Table of Contents.

Instruction summary

This section summarizes available mcx instructions, with hyperlinks to the descriptions in the manual.

Switches

Switches that affect variables and formatting of data files that are read and written.

−nc=# (nr=#)
−vvar=#
−show
−mmacroname(arg1,arg2,…)=expr(arg1,arg2,…) −w[l=string] fname | −bw[l=string] fname
−wap
−a[nr=#|:nc=#] nam | −ap nam
−av[ir,ic] vvar
−r~switches
−px[:nprec]
−pxc

Unary operators

Operators that act on the top level matrix and replace it with the result of the unary operator:

−p−p+n−(-p-n)
−pop −popu   −popb
−csum[:list]−rsum[:list]
−s#
−shft=#
−sort expr
−i | − iq
−1:n
−evl | −evc
−t−cc
−herm −real
−v2dia
−split nam row-markers column-markers
−rep:n1,n2
−roll:#1[,#2]
−pwr=#
−tp [nc~]list
−rot=strn
−roteu
−ylm~l=l[~sh|~sh2|~s2r|~2rs][~spin|~spin+o|~spin+oonly]
−array[#1,#2]   #,#,#,…
−sarray[#1,#2]   |   −sarrayr[#1,#2]   |   −sarrayc[#1,#2]   |   −sarrayz[#1,#2]  

Row and column Unary Operators

Row and column manipulations of the top-level array

−rowl list   −rowl:mirr
−coll list   −coll:mirr
−rowl:pf=fnam   −coll:pf=fnam   −rowl:ipf=fnam   −coll:ipf=fnam
−inc expr
−sub t,b,l,r−subs:# t,b,l,r−subv:# t,b,l,r
−e# expr1   expr2   …   expr#

Unary Operators treating data as discretized continuous functions of the first column

−diff[:opts]
−int[:opts] xlo list
−intrp[:opts] list
−smo width,xmin,xmax,dx
−abs
−max[:i|g]
−unx[:i1] #1,#2−unx2[:i1] #1,#2
−at[:i1] val expr
−nint[#1]

Binary Operators

Operator that replace the contents of the two matrices on the stack with the result of a binary operation. if they are added they must have the same number of rows and columns.

−tog−+−−−x−xe−de
−x3
−gevl   −gevc
−orthos
−ccat−rcat
−cross
−suba[#] t,b,l,r   -suba[#] t,l
−index

File comparison mode

Use -cmpf to compare numbers between two files with mixed text and numbers.

Repeated Iteration of Command Line Arguments

Loop over arguments inside [ .. ]

Return to Table of Contents.

Other resources

The source code to mcx can be found in the bitbucket repository.