Quickstart: Difference between revisions

From Alida
Jump to navigationJump to search
No edit summary
No edit summary
 
Line 1: Line 1:
Here we introduce Alida's operator concept with some code snippets of <code>ALDOperator</code>s
Here we introduce Alida's operator concept with some code snippets to give you a first impression of how to deal with Alida on the programming level.
and focus on Alida's capabilities to automatically generate user interfaces.


=  First operator =
* for Java snippets and more follow [[Java_quick|this]] link
* C++ snippets and interesting information on the implementation in C++ can be found [[C++_quick|here]]


As a first example of an Alida operator we implement the row or column wise
Notes on the installation of Alida can be found [[Installation|here]] and in the user manual accessible from [http://www2.informatik.uni-halle.de/agprbio/alida/downloads/manual/AlidaManual.pdf here].
sum for a 2D array of Doubles.
The class <code>MatrixSum</code> extending <code>ALDOperator</code> features three member variables
holding the input 2D array, an enum to indicate the mode of summation (<code>ROW</code> or <code>COLUMN</code>), and
an 1D array of the sums to be computed and returned by the operator.
Alida requires only to annotate these members with the @Parameter annotation
which declares
 
* the direction (<code>IN</code>, <code>OUT</code>, <code>INOUT</code>),
* whether the parameter is required,
* an optional textual description,
* and a label used, e.g. in the graphical user interface automatically generated
to execute the operator.
 
It is important to add a public standard constructor (without arguments)
to be able to use Java's reflection mechanism.
Finally, the abstract method <code>operate()</code> of <code>ALDOperator</code> has to be overridden
implementing the functionality of the operator.
 
 
 
<pre>
@ALDAOperator(genericExecutionMode=ALDAOperator.ExecutionMode.ALL,
level=ALDAOperator.Level.APPLICATION)
public class MatrixSum extends ALDOperator {
 
  /** Choose row or colum wise sum
    */
  public static enum SummarizeMode {
/** row wise */
ROW,
 
/** column wise */
COLUMN
  }
 
  /**
  * Input matrix
  */
  @Parameter( label= "Input matrix", required = true,
  direction = Parameter.Direction.IN, description = "Input matrix.")
  private Double[][] matrix;
 
  /**
  * Mode of summarizing
  */
  @Parameter( label= "Summarize mode", required = true,
  direction = Parameter.Direction.IN, description = "Sum over columns or rows?")
  private SummarizeMode summarizeMode = SummarizeMode.ROW;
 
  /**
  * 1D Array of sums.
  */
  @Parameter( label= "sums", 
  direction = Parameter.Direction.OUT, description = "Row or column wise sums.")
  private Double[] sums = null;
 
/**
* Default constructor.
* @throws ALDOperatorException
*/
public MatrixSum() throws ALDOperatorException {
}
 
/**
* Constructor.
*
* @param matrix Input matrix.
* @throws ALDOperatorException
*/
public MatrixSum(Double[] [] matrix) throws ALDOperatorException {
this.matrix = matrix;
}
 
@Override
protected void operate() {
if ( matrix == null )
sums = null;
 
// calculate sums
if ( summarizeMode == SummarizeMode.ROW ) {
sums = new Double[matrix.length];
for ( int row = 0 ; row < matrix.length ; row++ ) {
sums[row] = 0.0;
for ( int col = 0 ; col < matrix[0].length ; col++ )
sums[row] += matrix[row][col];
}
} else {
sums = new Double[matrix[0].length];
for ( int col = 0 ; col < matrix[0].length ; col++ ) {
sums[col] = 0.0;
for ( int row = 0 ; row < matrix.length ; row++ )
sums[col] += matrix[row][col];
}
}
}
</pre>
 
 
 
These are the basic requirements for the operator to be used on the programming level.
An example of this use is included in the example in the next section.
 
If we further annotate the class with
<pre>
@ALDAOperator(genericExecutionMode=ALDAOperator.ExecutionMode.ALL)
</pre>
this is all needed to also facilitate
execution of this operator via a graphical and a command line user interface
automatically generated by Alida.
(Setting <code>level=ALDAOperator.Level.APPLICATION</code> declares this operator an application
which is used in the GUI to control display of available operators.)
 
 
==  Invocation via a graphical user interface ==
 
Alida comes with one single application to execute Alida operators
with a automatically generated graphical user interface which may be
started from command line by
<pre>
java de.unihalle.informatik.Alida.tools.ALDOpRunnerGUI
</pre>
 
This will pop up a window to choose an operator to execute.
Arranged according to the package structure all operators allows to be executed
via the graphical user interface according to their <code>genericExecutionMode</code>
are displayed.
Initially packages are unfolded up to a predefined depth.
Unfold the demo package, select <code>MatrixSum</code>, and choose the "Configure Operator" button.
This will pop up another window which allows you to configure the input parameters
of the operator.
Important note: After finishing to input the data matrix entering the final matrix elements
you have to select a previous matrix element due to subtle AWT details.
For the enumeration to select the mode Alida has automatically generated
a combo box to allow convenient selections.
If you are finished with the parameter configuration you want to invoke the operator
using the run button.
On completion of <code>MatrixSum</code> the interface will pop up the result window which allows you
to inspect the outcome of the operation.
 
==  Invocation via command line ==
 
The command line user interface of Alida allows to invoke all Alida operator
properly annotated to allows generic execution.
 
You may invoke the matrix summation operator by
<pre>
java de.unihalle.informatik.Alida.tools.ALDOpRunner MatrixSum matrix='[[1,2,3],[4,5,6]]' sums=-
</pre>
which returns as result on standard output
<pre>
sums = [6.0,15.0]
</pre>
 
Parameter values are specified as name=value pairs.
Alida's syntax for 2D array should be self-explanatory  from this example.
As the mode of summation is not supplied as a parameter its default is used
 
Note, the command
<pre>
java de.unihalle.informatik.Alida.tools.ALDOpRunner MatrixSum matrix='[[1,2,3],[4,5,6]]'
</pre>
will return no output as the command line user interface returns only output parameters requested.
 
The enumeration defined in <code>MatrixSum</code> is supported by the
user interface without further action required as shown in the next example.
This also demonstrates redirection of output
to a file, sums.out in this case.
 
<pre>
java de.unihalle.informatik.Alida.tools.ALDOpRunner MatrixSum matrix='[[1,2,3],[4,5,6]]'
summarizeMode=COLUMN sums=@sums.out+
</pre>
Input can be read from file as well:
<pre>
java de.unihalle.informatik.Alida.tools.ALDOpRunner MatrixSum matrix=@data sums=-+
</pre>
 
where the file data contains the string defining the matrix, e.g., <code>[[1,2,3],[4,5,6]]</code>
 
= Adding more features to an operator =
 
We now generalize this example to realize not only summation over rows or
columns, but arbitrary summarizing operations.
This shows Alida's feature to allow an operator as parameter of another operator.
 
== Implementation ==
 
First we generalize <code>ALDArraySum</code> to the operator <code>ApplyToMatrix</code>
which also takes a 2D array and an enum indicating the mode of marginalization (<code>ROW</code> or <code>COLUMN</code>).
It takes an additional input parameter which specifies the operation to be applied on each
row or column.
 
This parameter is itself an Alida operator and of type <code>ALDSummarizeArrayOp</code>
which is implemented as an abstract class.
This abstract operator defines a summarizing operator
which takes a 1D array as input and returns a summarizing scalar.
As this is an abstract class there is no need to override the <code>operate()</code>
method, however some getter and setter methods are provided.
 
 
 
<pre>
  @Parameter( label= "Input 1D array", required = true,
  direction = Parameter.Direction.IN, description = "Input array (1D).")
  protected Double[] data;
 
  /**
  * Summarizing scalar
  */
  @Parameter( label= "Summarizing scalar", 
  direction = Parameter.Direction.OUT, description = "Summarizing scalar of the 1D arra")
  protected Double summary = null;
 
/**
* Default constructor.
* @throws ALDOperatorException
*/
public ALDSummarizeArrayOp() throws ALDOperatorException {
}
 
/**
* Returns the 1D array
* @return data array
*/
public Double[] getData() {
return this.data;
}
 
/**
* Sets the 1D array
* @param data
*/
public void setData( Double[] data) {
this.data = data;
}
 
</pre>
 
 
Now we add concrete examples of such a summarizing operation, in this case
summation (<code>ALDArraySum</code>), to return the mean (<code>ALDArrayMean</code>), and the minimum (<code>ALDArrayMin</code>).
Each implements the  <code>operate()</code> method and has to supply a standard constructor.
In this example we add another constructor for convenience.
This operators are declared as operators on the standard in contrast to
application level, as they are not expected to be invoked as an application.
However, setting the level to standard in the menu of the graphical user interface
stills allows their execution.
When extending the abstract super class it is necessary to annotate the
class with <code>@ALDDerivedClass</code> in order to allow Alida's dataIO mechanism to find the derived class
in the automatically generated user interface.
This holds for other parameter types as well.
More specifically, if an instance of a class is to be supplied in an automatically
generated user interface as a value for a parameter of one of its super classes,
Alida requires the annotation <code>@ALDDerivedClass</code>.
 
 
 
<pre>
@ALDDerivedClass
@ALDAOperator(genericExecutionMode=ALDAOperator.ExecutionMode.ALL,
        level=ALDAOperator.Level.STANDARD)
public class ALDArraySum extends ALDSummarizeArrayOp {
 
    @Override
    protected void operate() {
        summary = 0.0;
        for ( int i = 0 ; i < data.length ; i++ )
            summary += data[i];
    }
 
    /**
    * Default constructor.
    * @throws ALDOperatorException
    */
    public ALDArraySum() throws ALDOperatorException {
    }
 
</pre>
 
 
Now we are ready to implement
the <code>ApplyToMatrix</code> operator, which also demonstrates supplemental parameters.
This supplementals, e.g., control debugging output or returning of intermediate results.
For demo purposes we declare a supplemental input parameter <code>returnElapsedTime</code>.
If it is set to true the operator will return the elapsed time in a second
supplemental parameter with direction output.
 
Again, the operation is implemented in the  <code>operate()</code> method and the remainder of the
class supplies getter and setter methods for convenience.
The  <code>operate()</code> method give also an example of the invocation of an operator on the
programming level.
In this case, an instance of the operator is already passed as a parameter.
Its parameters are set, in this case each 1D array to be summarized in turn.
Upon return from the method <code>runOp()</code> the results may be retrieved from the operator object,
in this example with the <code>getSummary()</code> method.
Besides getter and setter methods as implemented in each operator
Alida provides also a generic get and set methods applicable to
all parameters of an operator.
Note, that the operator is not invoked by its  <code>operate()</code> method, but via
the <code>runOp()</code> method implemented the base class <code>ALDOperator</code>.
This methods validates the parameters before invocation of  <code>operate()</code>.
Furthermore, it take all necessary measures for Alida's processing
history which automatically logs
all manipulative actions on the data and corresponding parameter settings.
 
 
 
<pre>
@ALDAOperator(genericExecutionMode=ALDAOperator.ExecutionMode.ALL,
            level=ALDAOperator.Level.APPLICATION)
public class ApplyToMatrix extends ALDOperator {
 
    /** Choose row or colum wise sum
      */
    public static enum SummarizeMode {
      /** row wise */
      ROW,
      /** column wise */
      COLUMN
    }
 
    /**
    * Input matrix
    */
    @Parameter( label= "Input matrix", required = true,
          direction = Parameter.Direction.IN, description = "Input matrix.")
    private Double[][] matrix;
 
    /**
    * Mode of summarizing
    */
    @Parameter( label= "Summarize mode", required = true,
          direction = Parameter.Direction.IN, description = "Sum over columns or rows.")
    private SummarizeMode summarizeMode = SummarizeMode.ROW;
 
    /**
    * Summarizing opererator
    */
    @Parameter( label= "Summarizing operator", required = true,
          direction = Parameter.Direction.IN, description = "Specifies the summarizing operation to apply")
    private ALDSummarizeArrayOp summarizeOp;
 
    /**
    * 1D Array of summaries.
    */
    @Parameter( label= "summaries", 
          direction = Parameter.Direction.OUT, description = "Row or column wise summaries")
    private Double[] summaries = null;
 
    /**
    * Supplemental to request elapsed time to be returned
    */
    @Parameter( label= "Return elapsed time",
          direction = Parameter.Direction.IN, description = "Request elapsed time consumed to be returned",
        supplemental=true)
    private boolean returnElapsedTime = false;
 
    /**
    * Elpased time
    */
    @Parameter( label= "Elapsed time", 
          direction = Parameter.Direction.OUT, description = "Elapsed time of operation in milliseconds",
        supplemental=true)
    private long elapsedTime;
 
    /**
    * Default constructor.
    * @throws ALDOperatorException
    */
    public ApplyToMatrix() throws ALDOperatorException {
    }
 
    /**
    * Constructor.
    *
    * @param matrix    Input matrix.
    * @throws ALDOperatorException
    */
    public ApplyToMatrix(Double[] [] matrix) throws ALDOperatorException {
        this.matrix = matrix;
    }
 
    @Override
    protected void operate() throws ALDOperatorException,ALDProcessingDAGException {
        if ( returnElapsedTime )
            elapsedTime = System.currentTimeMillis();
 
        if ( matrix == null )
            summaries = null;
 
        // calculate summaries
        if ( summarizeMode == SummarizeMode.ROW ) {
            summaries = new Double[matrix.length];
            for ( int row = 0 ; row < matrix.length ; row++ ) {
                summarizeOp.setData(matrix[row]);
                summarizeOp.runOp();
                summaries[row] = summarizeOp.getSummary();
            }
        } else {
            summaries = new Double[matrix[0].length];
            Double[] tmp = new Double[matrix.length];
            for ( int col = 0 ; col < matrix[0].length ; col++ ) {
                for ( int row = 0 ; row < matrix.length ; row++ )
                    tmp[row] = matrix[row][col];
 
                summarizeOp.setData(tmp);
                summarizeOp.runOp();
                summaries[col] = summarizeOp.getSummary();
            }
        }
 
        if ( returnElapsedTime )
            elapsedTime = System.currentTimeMillis() - elapsedTime;
    }
   
    // ==============================================================
    // Getter and setter methods
    /** Get value of returnElapsedTime.
      * Explanation: Request elapsed time consumed to be returned.
      * @return value of returnElapsedTime
      */
    public boolean getReturnElapsedTime(){
        return returnElapsedTime;
    }
 
    /** Set value of returnElapsedTime.
      * Explanation: Request elapsed time consumed to be returned.
      * @param value New value of returnElapsedTime
      */
    public void setReturnElapsedTime( boolean value){
        this.returnElapsedTime = value;
    }
</pre>
 
 
 
==  Invocation via a graphical user interface ==
 
If the graphical interface is still running just select our new operator
and begin to configure it.
For the parameter summarizing operator you have a choice of all operators extending
the abstract operator <code>ALDSummarizeArrayOp</code>.
All which is necessary on the implementation side is proper annotation of the extending
classes with <code>@ALDDerivedClass</code>.
As the selected operator may have its own parameters you may want to configure it.
In our example this is not necessary as the input array is, of course, supplied
by the <code>ApplyToMatrix</code> operator.
Do not forget to input your data before hitting the run button.
After return, again a result window give you the results of the operation.
Note, if you did not tick Return elapsed time" this window will show zero
for the time elapsed as the operator has not been request to stop the time.
 
 
==  Invocation via command line ==
 
When invoking the <code>ApplyToMatrix</code> operator from command line
we have to handle derived classes as value for parameters.
In the graphical user interface Alida features a combo box where
we may choose from.
In the command line interface Alida allows to prefix the value of a parameter
with a derived class to be passed to the operator.
This is necessary as Alida as, of course, no way to itself
decide if and which derived class is to be used.
Alida's syntax is to enclose the class name in a dollar sign and a colon.
As evident in the following example, abbreviations are of the fully
qualified class name are accepted as long as they are unambiguous.
<pre>
java de.unihalle.informatik.Alida.tools.ALDOpRunner Apply \
matrix='[[1,2,3],[4,5,6]]' \
summarizeMode=ROW \
summarizeOp='<math>ALDArrayMean:{}' \
summaries=-
</pre>
results in
<pre>
summaries = [2.0,5.0]
</pre>
 
 
<code>ALDOpRunner</code> may be persuaded to show all operators derived from <code>ALDSummarizeArrayOp</code>
and known within the user interface if we enter an invalid class name:
<pre>
java de.unihalle.informatik.Alida.tools.ALDOpRunner \
Apply matrix='[[1,2,3],[4,5,6]]' \
summarizeMode=ROW summarizeOp='</math>dd:{}' \
summaries=-
</pre>
yields
<pre>
ALDStandardizedDataIOCmdline::readData found 0 derived classes matching <dd>
      derived classes available:
de.unihalle.informatik.Alida.demo.ALDArrayMean
de.unihalle.informatik.Alida.demo.ALDArrayMin
de.unihalle.informatik.Alida.demo.ALDArraySum
ERROR: reading parameter <summarizeOp> returns null
</pre>
 
 
Supplemental parameters are handled like other parameters
<pre>
java de.unihalle.informatik.Alida.tools.ALDOpRunner Apply \
matrix='[[1,2,3],[4,5,6]]' \
summarizeMode=COLUMN \
summarizeOp='<math>ALDArrayMin:{}' \
summaries=- \
returnElapsedTime=true \
elapsedTime=-
</pre>
gives
<pre>
summaries = [1.0,2.0,3.0]
elapsedTime = 4
</pre>
 
 
 
=  Adding more data types as parameters =
 
Alida provides automatic IO of primitive data types, enumerations, arrays, collections,
and operators.
In addition so called parameterized classes are supported.
Any Java class may be declared to be a parameterized class in Alida
by annotating the class <code>@ALDParametrizedClass</code> as shown in the
class <code>ExperimentalData</code>.
All member variables to be known to and handled by Alida's user interface
simply need to be annotated with <code>@ALDClassParameter</code>.
 
Here we implement a toy version of experimental data <code>ExperimentalData</code>.
A complete experiment consists of a number of independent repetitions of
sub experiments.
In each of these the same features (measurements) are recorded.
The measurements a represented in
a 2D array of Doubles, where each column represents
one sub experiment and the rows the distinct features.
The measurements may be normalized which is indicated by the
normalized member variable.
 
The class is annotated by <code>@ALDParametrizedClass</code>, and
and all members to be handle in Alida'a user interfaces are
to be annotated with <code>@ALDParametrizedClass</code>.
The label field has the same semantics as for parameters of operators.
These annotations are the only implementational overhead
to allow Alida to automatically generate user interfaces
where the parameterized class acts a a parameter.
 
 
 
<pre>
@ALDParametrizedClass
@ALDMetaInfo(export=ALDMetaInfo.ExportPolicy.MANDATORY)
public class ExperimentalData {
    @ALDClassParameter(label="description")
    private String description = null;
 
    @ALDClassParameter(label="data")
    private Double[][] data = null;
 
    /** are the data normalized
      */
    @ALDClassParameter(label="Is normalized")
    private boolean normalized = false;
 
    /** Standard constructor is needed
      */
    public ExperimentalData() {
    }
 
    /** Constructor for an experiment.
      * Normalized is assumed to be false.
      *
      * @param  description  a textual desciption of the experiment
      * @param  data  measurements
      */
    public ExperimentalData( String description, Double[][] data) {   
        this( description, data, false);
    }
 
    /** Constructor for an experiment.
      *
      * @param  description  a textual desciption of the experiment
      * @param  data  measurements
      * @param  normalized  are the data normalized
      */
    public ExperimentalData( String description, Double[][] data, boolean normalized) {   
        this.normalized = normalized;
        this.description = description;
        this.setData( data, normalized);
    }
</pre>
 
 
This is shown below for a simple normalizing operator <code>NormalizeExperimentalDataOp</code>
which takes experimental data as input an returns a new instance
of <code>ExperimentalData</code> which contains normalized data.
 
 
 
<pre>
@ALDAOperator(genericExecutionMode=ALDAOperator.ExecutionMode.ALL,
                level=ALDAOperator.Level.APPLICATION)
public class NormalizeExperimentalDataOp extends ALDOperator {
 
    /**
    * Input data
    */
    @Parameter( label= "Experimental data", required = true,
          direction = Parameter.Direction.IN, description = "Experimental data to be normalized")
    private ExperimentalData experiment = null;
 
    /**
    * Normalized experiment to be returned
    */
    @Parameter( label= "Normalized experiment", 
          direction = Parameter.Direction.OUT, description = "Normalized experiment")
    private ExperimentalData result = null;
 
    /**
    * Default constructor.
    * @throws ALDOperatorException
    */
    public NormalizeExperimentalDataOp() throws ALDOperatorException {
    }
 
    /**
    * Constructor.
    *
    * @param experiment    Experimental data
    * @throws ALDOperatorException
    */
    public NormalizeExperimentalDataOp(ExperimentalData experiment) throws ALDOperatorException {
        this.experiment = experiment;
    }
 
    @Override
    protected void operate()  throws ALDOperatorException,ALDProcessingDAGException {
       
        ApplyToMatrix normalizeOp = new ApplyToMatrix( experiment.getData());
        normalizeOp.setSummarizeMode( ApplyToMatrix.SummarizeMode.ROW);
        normalizeOp.setSummarizeOp( new ALDArrayMean());
        normalizeOp.runOp();
 
        Double[][] normalizedData = (Double[][])(experiment.getData().clone());
        for ( int e = 0; e < experiment.getNumExperiments(); e++ ) {
            for ( int f = 0 ; f < experiment.getNumFeatures()  ; f++ ) {
                normalizedData[f][e] -=  normalizeOp.getSummaries()[f];
            }
        }
 
        result = new ExperimentalData( experiment.getDescription() + " (Normalized)", normalizedData, true);
    }
</pre>
 
 
 
This mechanism applies in a recursive fashion, i.e. a parameterized class may
(recursively) contain a member variable which itself is a parametrized class.
Likewise, an operator acting as a parameter of another operator
may in turn have a parameter of type <code>ALDOperator</code>.
 
==  Invocation via a graphical user interface ==
 
Invoking and configuring <code>NormalizeExperimentalDataOp</code> from the graphical user interface
shows as the only required parameter the experimental data.
This parameterized class can be configured in a separate  window
very similar to to configuration of operators.
Likewise the resulting normalized experimental data
may be inspected in their own window.
 
Obviously this is a toy example, as we would not expect the measurements to
be entered manually, but rather stored and read from file in a specialized format.
This is one of the rare cases where
custom data IO provider need to be implemented, in this
case for <code>ExperimentalData</code>.
 
 
==  Invocation via command line ==
 
Again, invocation from command line is provided by Alida in an automatic
way with no further implementational overhead.
The syntax for parameterized classes es a comma separated list of name=value pairs
enclosed in curly brackets where name refers to annotated member variables of
the parameterized class.
 
<pre>
java de.unihalle.informatik.Alida.tools.ALDOpRunner NormalizeExperimentalDataOp \
experiment='{data=[[1,2,3],[2,2,2],[100,103,110]],description="Demo experiment"}' \
result=-
</pre>
yields
<pre>
result = { normalized = true ,
          description = "Demo experiment" (Normalized) ,
          data = [[-1.0,0.0,1.0],[0.0,0.0,0.0],
                  [-4.333333333333329,-1.3333333333333286,5.666666666666671]] }
</pre>
 
If a class derived from <code>ExperimentalData</code> was to be supplied to the operator,
the curly brackets can be prefixed by a derive class definition starting with a dollar sign
and ending with a colon as shown for the summarizing operators above.

Latest revision as of 17:19, 9 March 2012

Here we introduce Alida's operator concept with some code snippets to give you a first impression of how to deal with Alida on the programming level.

  • for Java snippets and more follow this link
  • C++ snippets and interesting information on the implementation in C++ can be found here

Notes on the installation of Alida can be found here and in the user manual accessible from here.