Your first MAST-ML run¶
It’s time to conduct your very first MAST-ML run! First, we will set up the most basic input file, which will only import your data and input file, and do nothing else except copy the input files to the results directory and output a basic histogram of the target data. Open the example_input.conf file (or create your own new file), and write the following in your input file:
Example:
[GeneralSetup]
input_features = Auto
input_target = Reduced barrier (eV)
randomizer = False
metrics = Auto
input_other = Host element, Solute element, predict_Pt
The General Setup section contains high-level control about how your input data file is parsed. Additional details of each parameter can be found in the MAST-ML Input File section in this documentation. Briefly, setting “input_features” to “Auto” will automatically assign all columns to be part of the X feature matrix, except those that are associated with target_feature or not_input_features. The option “randomizer” will shuffle all of your y-data, which can be useful for running a “null” test. The “metrics” option is used to denote which metrics to eventually evaluate your models on, such as mean_absolute_error. Using “Auto” provides a catalogue of standard metrics which is generally sufficient for many problems. Finally, the “not_input_features” field is used to denote any feature columns you don’t want to use in fitting. If some columns contain text notes, these will need to be added here too.
There are two ways to execute a MAST-ML run. The first is to run it via a Terminal or IDE command line by directly calling the main MAST-ML driver module. Here, the python -m (for module) command is invoked on the mastml.masml_driver module, and the paths containing the input file and data file are passed in. Lastly, the argument -o (for output) is used together with the path to put all results files and folders.
Example:
python3 -m mastml.mastml_driver tests/conf/example_input.conf tests/csv/example_data.csv -o results/mastml_tutorial
The second way is to run MAST-ML through a Jupyter notebook by importing mastml and running the mastml_driver main() method and supply the paths to the input file, data file
Example:
import mastml_driver
conf_path = 'tests/conf/example_input.conf'
data_path = 'tests/conf/example_data.csv'
results_path = 'results/mastml_tutorial'
mastml_driver.main(conf_path, data_path, results_path)
Let’s examine the output from this first run. Below is a screenshot of a Mac directory output tree in the results/mastml_tutorial folder. Note that you can re-use the same output folder name, and the date and time of the run will be appended so no work will be lost. Each level of the directory tree corresponds to a step in the general supervised learning workflow that MAST-ML uses. The first level is general data input and feature generation, the second level is numerical manipulation of features, and the third level is selection of features. Since we did not do any feature manipulation in this run, the output selected.csv, normalized.csv and generated_features.csv are all the same, and are the same file as the copied input data file, example_data.csv. In the main directory tree, there is also a log.log and errors.log file, which summarize the inner details of the MAST-ML run and flag any errors that may have occurred. There are two .html files which provide very high-level summaries of data plots and file links that may be of interest, to make searching for these files easier. Finally, there is some generated data about the statistics of your input target data. A histogram named target_histogram.png is created, and basic statistical summary of your data is saved in the input_data_statistics.csv file.


Liszt is embedded in Lua. Currently, this means that we need to include a line at the top of their programs to import the compiler.
import 'compiler.liszt'
L.default_processor
In order to specify which processor Liszt should execute on, we can choose to set the default processor (L.CPU
or L.GPU
) immediately after importing the compiler. If we omit this command entirely, Liszt will default to executing on the CPU.
L.default_processor = L.GPU
L.require
Libraries and other Liszt files can be imported using Liszt's require statement. (The behavior mimics Lua's require statement) For instance, if we want to import the file trimesh.t
located in the folder subdir
we would write
local TriMesh = L.require 'subdir.trimesh'
Liszt has the following primitive types
L.bool L.float L.double L.int L.uint64
Additionally, Liszt has key
types. A key-value encodes a reference to a row of some relation, making keys parameterized types
L.key(relation)
As a convenience, if we pass a relation rel
into an API where it was expecting a type, Liszt will automatically convert that relation into L.key(rel)
.
Lastly, both primitive types and key types can be grouped into vectors or matrices using one of the following two type constructors
L.vector(base_type, N)
L.matrix(base_type, Nrow, Ncol)
For convenience, we define aliases for common vector and matrix types. We use the pattern L.vec[#dimension][type]
for vectors and L.mat[#row]x[#col][type]
for matrices. For square matrices we also define L.mat[N][type]
. Some examples follow
L.vec3d -- a vector of 3 doubles
L.mat4f -- a 4x4 matrix of floats
L.mat4x4f -- another alias for a 4x4 matrix of floats
L.mat2x3i -- a 2x3 matrix of integers
L.vec3b -- a vector of 3 booleans
Liszt types are Lua objects, which means they can be assigned to and passed around as Lua variables. To help the code introspect on types when used in this way, the type objects provide a collection of methods.
L.is_type(obj)
returns true when the obj is a Liszt type.
typ:isscalar()
typ:isvector()
typ:ismatrix()
Every Liszt type is either a matrix, vector, or scalar. If the type is a vector, we can get its size using typ.N
. If the type is a matrix, we can get its dimensions using typ.Nrow
and typ.Ncol
.
typ:basetype()
For vector and matrix types, the base type is the scalar type parameter. For scalar types, this function returns the type it was called on.
typ:isvalue()
returns true when the base type is a primitive, i.e. L.bool
, L.float
, L.double
, L.int
, or L.uint64
.
typ:isintegral()
returns true when the base type is L.int
or L.uint64
.
typ:isnumeric()
returns true when the base type is L.float
, L.double
, L.int
, or L.uint64
.
typ:islogical()
returns true when the base type is L.bool
.
typ:iskey()
returns true when the base type is a key. The relation argument to the key type can be retreived as typ.relation
.
typ:isPrimitive()
returns true when the type is a primitive. (both scalar and a value type)
typ:isscalarkey()
returns true when the type is a key, but not a vector of keys or matrix of keys.
local c = L.Constant(typ, initial_value)
Liszt allows programmers to create constant values within the Lua scope. These values must be explicitly typed.
Whenever either a Constant or a Lua value is used inside of a Liszt function, the value is substituted inline into the Liszt function as a constant. For instance, in the following example, both k
and kf
are captured and inlined when foo()
is defined. So when foo()
is mapped over the cells, both lines compute c.f += 23 * c.g
even though the value of the Lua variable k
has later been changed.
local kf = L.Constant(L.float, 23)
local k = 23
local liszt foo ( c : cells )
c.f += kf * c.g
c.f += k * c.g
end
k = 11
cells:map(foo)
Constants provide us with two benefits. 1) Constants allow us to explicitly type constant values. (we do not know for sure what value k will be assigned above) 2) Constants allow us to explicitly document values that we intend as constants, so that our code is more easily understandable to other programmers.
L.is_constant(obj)
Test whether a Lua object is a constant or not
constant:get()
Retreive the Lua value of the constant
local g = L.Global(typ, initial_value)
Liszt allows programmers to create 'global' variables, i.e. data that is shared across all relations, rows of relations, and functions mapped over those relations.
L.is_global(obj)
Test whether a Lua object is a global or not.
global:set(val)
Set the value of a global variable from Lua code.
global:get()
Get the value of a global variable from Lua code. If you're performance tuning, be aware that get()
is a blocking call. If necessary, the main control thread will hang while waiting for the newest value of the global.
local rel = L.NewRelation({
name = 'rel',
mode = ['PLAIN' | 'GRID' | 'ELASTIC'],
[size = n_rows,] -- required if mode ~= 'GRID'
[dims = {nx,ny,...},] -- required if mode == 'GRID'
[periodic = {px,py,...},] -- optional if mode == 'GRID'
})
Liszt relations are created by passing a table of named arguments to the NewRelation
constructor. Descriptions of each argument follow
name
assigns a name to the relation for debugging. We recommend setting this to be the same as the name of the variable you assign the relation to.mode
a relation can exist in one of 4 modes, and can be created initially in 3 of those 4 modes. If this argument is omitted the mode is inferred as 'PLAIN'
if a size
argument is provided, or 'GRID'
if a dims
argument is provided.size
specifies the number of rows in a 'PLAIN'
or 'ELASTIC'
relation.dims
specifies a list of dimension sizes for a 'GRID'
relation. Either two numbers can be provided (a 2d grid) or three (a 3d grid). Other numbers of dimensions are not supported.periodic
is an optional argument when creating a 'GRID'
relation. It expects a liszt parallel to dims
with boolean entries. If the entry is true for a given dimension, then Liszt will wrap around all indices in that dimension. (e.g. consider indexing a row of a 2d relation created with periodic={true,false}
and dims={10,12}
. The key [13,4]
will be automatically wrapped around into key [3,4]
, but trying to access data at key [4,13]
will cause an error)As mentioned, a relation in Liszt can be in one of 4 different states, never more than one at a time.
Plain Grouped Grid Elastic
Not all functionality is available in every relation mode.
L.is_relation(obj)
Test whether a Lua object is a relation or not.
local str = rel:Name()
Retrieve the name of a relation.
local n = rel:Size()
Retrieve the number of rows in a relation. If the relation is in Grid mode, then this is the product of the dimensions.
rel:Print()
print the contents of this relation's fields to the console (for debugging).
rel:isPlain()
Test whether a relation is in Plain mode.
Plain mode relations can be grouped, putting them into Grouped mode. Elastic and Grid mode relations cannot be grouped.
rel:GroupBy(field)
GroupBy()
expects either a field defined on relation rel
or the name (i.e. a string) of a field defined on rel
as its argument. This field should have type L.key(src_rel)
, and should already be sorted by the key values in this field. (We plan to eventually support automatically sorting this data, but haven't yet done so.)
for dest_key in L.Where(grouped_field, source_key) do
...
end
Once a relation dest_rel
has been grouped by a field grouped_field
of type L.key(source_rel)
, we can find all the keys of dest_rel
where dest_key.grouped_field == source_key
given a key from source_rel
. We do this using a query loop, as shown above.
For example, we could group edges by their tail vertex, and then take a neighborhood average, using a query loop.
edges:GroupBy('tail')
local liszt foo(v : vertices)
var sum = 0
for e in L.Where(edges.tail, v) do
sum += e.head.f
end
v.f_sum = sum
end
For convenience, Liszt allows us to compose key field accesses with L.Where()
queries. For instance, we could rewrite the above loop instead as
for nv in L.Where(edges.tail, v).head do
sum += nv.f
end
In practice, these query loops are hidden behind macros so that a programmer writes something more like
for nv in v.neighbors do
sum += nv.f
end
rel:isGrouped()
Test whether a relation is in Grouped mode
rel:GroupedKeyField()
Return the field that rel
is currently grouped by. If rel
is not grouped, then this call returns nil
.
rel:isElastic()
Test whether a relation is in Elastic mode.
rel:isFragmented()
Test whether a relation is fragmented. Many functions will fail if called on a fragmented relation or a fragmented relation's fields. (e.g. I/O related functions) Only Elastic mode relations can be fragmented.
rel:Defrag()
When called on a fragmented Elastic mode relation, Defrag()
will ensure that the rows of the relation are densely packed in memory.
Grid mode relations support a special way of accessing neighboring elements apart from fields of keys. This functionality is provided by the L.Affine
topological join.
local dest_key = L.Affine(destination_grid, affine_matrix, source_key)
L.Affine
can only be called inside of a Liszt function. It transforms the source_key
into a key of type L.key(destination_grid)
. Specifically, if [xid,yid]
or [xid,yid,zid]
are the indices of the source_key
, then the indices of the resulting key are produced by applying the affine transformation matrix. If the source grid has m
dimensions and the destination grid has n
dimensions, then the affine transformation matrix should have n
rows and m+1
columns. The last column of the matrix encodes the translational offset, so that the transformation computation consists of multiplying by the first nxm
block and then adding the last nx1
column. Finally, the supplied affine_matrix
must be a literal, not a variable matrix value.
Some example uses of L.Affine
follow.
local liszt copy_from_right( c : cells )
c.f_copy = L.Affine(cells, {{1,0,1},
{0,1,0}}, c).f
end
This example copies data over from the right neighbor in a 2d grid.
local liszt cell_to_vertex( c : cells )
var v = L.Affine(vertices, {{1,0,0},
{0,1,0}}, c)
end
This example produces the vertex with the same indices as the cell, and does nothing in particular with it.
local liszt up_step( cc : coarse_cells )
var fc = L.Affine(fine_cells, {{2,0,0},
{0,2,0}}, cc)
var sum = fc.f
+ L.Affine(fine_cells, {{1,0,1},
{0,1,0}}, fc).f
+ L.Affine(fine_cells, {{1,0,0},
{0,1,1}}, fc).f
+ L.Affine(fine_cells, {{1,0,1},
{0,1,1}}, fc).f
cc.f = sum / 4.0
end
This example performs an integration of a field stored at 4 fine cells into the corresponding coarse cell. (e.g. in a multi-grid scheme) In practice, these L.Affine
calls would probably be hidden behind macros, producing code more like the following
local liszt up_step( cc : coarse_cells )
var fc = cc.fine
cc.f = ( fc.f + fc(1,0).f + fc(0,1).f + fc(1,1).f ) / 4.0
end
rel:isGrid()
Test whether a relation is in Grid mode.
rel:Dims()
Retrieve a copy of the dims
list used to create this grid relation. If called on a relation not in Grid mode, then { rel:Size() }
is returned instead.
rel:nDims()
Return 2
or 3
identifying how many dimensions this grid has. If called on a relation not in Grid mode, then 1
will be returned
rel:Periodic()
Retreive a copy of the periodic
list specified when creating this grid relation. If called on a relation not in Grid mode, then { false }
is returned instead.
So long as a relation is not in Elastic mode, we can define subsets of the relation.
rel:NewSubsetFromFunction(name, lua_function)
Define a new subset of rel
with name name
defined by lua_function
as follows. lua_function
is called once for each row and is expected to either return true (include this row in the subset) or false (exclude it); lua_function()
is given arguments lua_function(id, [yid, [zid]])
depending on how many dimensions rel
has.
NOTE: id conventions for defining subsets are currently subject to change; we expect the whole I/O system to change dramatically as Liszt incorporates support for distributed runtimes.
Once defined, a subset can be accessed as rel.subset_name
.
rel:hasSubsets()
Test whether a relation has subsets defined on it.
L.is_subset(obj)
Test whether a Lua object is a Liszt subset.
subset:Relation()
return the relation that subset
is a subset of.
subset:Name()
return the name of the subset.
subset:FullName()
return the name of the full relation and subset concatenated: "rel_name.subset_name"
rel:NewField(name, type)
Create a field on a relation with the given name
and type
. The field will now be accessible via rel.name
. (as a convenience, rel:NewField()
returns the newly created field, allowing for method chaining, as in rel:NewField(...):Load(...)
)
L.is_field(obj)
Test whether a Lua object is a field or not.
field:Name()
return the name of the field.
field:FullName()
return the name of the relation and field concatenated: "rel_name.field_name"
field:Relation()
return the relation that this field is defined on.
field:Size()
return the size of the relation that this field is defined on.
field:Type()
return the type of this field.
field:Print()
print the contents of this field to the console (for debugging).
rel:Copy({from = f1, to = f2})
copy the contents of field f1
into field f2
(assuming both are fields of relation rel
). f1
and f2
may be supplied as either field objects or strings identifying names of fields.
rel:Swap(f1,f2)
swap the contents of field f1
into field f2
(assuming both are fields of relation rel
). f1
and f2
may be supplied as either field objects or strings identifying names of fields.
Load()
is used to initialize field data. It can be used in 3 different ways.
field:Load(constant)
field:Load(lua_list)
field:Load(lua_function)
The first variant assigns the value constant
for every row of the relation. The second variant takes a Lua list of values as its argument; the list must have the right number of entries #lua_list == field:Size()
. The last form takes a function that is called once for each row and is expected to return the value to initialize that row's entry to; lua_function()
is given arguments lua_function(id, [yid, [zid]])
.
NOTE: id conventions for loading are currently subject to change; we expect the whole I/O system to change dramatically as Liszt incorporates support for distributed runtimes.
As an example, the following function initializes every row except the first row with temperature 0
. The first row gets temperature 1000
.
vertices.temperature:Load(function(i)
if i == 0 then return 1000 else return 0 end
end)
field:Dump({})
Opposite of loading via a list; this function returns the contents of field
converted into a Lua list value.
field:DumpFunction(lua_function)
The argument function lua_function
is called once for each row, and passed arguments lua_function(value, id, [yid, [zid]])
depending on how many dimensions field:Relation()
has.
NOTE: id conventions for dumping are currently subject to change; we expect the whole I/O system to change dramatically as Liszt incorporates support for distributed runtimes.
As an example, consider dumping velocity from a grid and printing it to the console.
cells.velocity:DumpFunction(function(v, xid, yid)
print('cell at ', xid, yid, ' has velocity ', v[1], v[2])
end)
Sometimes, we'd like to be able to dump multiple fields from a relation at the same time.
rel:DumpJoint(fields_list, lua_function)
DumpJoint()
calls lua_function
once for each row of rel
, with row ids and values for all of the requested fields. These arguments are supplied in the order lua_function(ids, [field1_value, field2_value, ...])
. The argument ids
is a Lua list containing between 1 and 3 values depending on the number of dimensions rel
has. fields_list
is a list of either field objects or strings identifying particular fields. The values passed to lua_function
are passed in the same order as the fields are listed in fields_list
.
NOTE: id conventions for dumping are currently subject to change; we expect the whole I/O system to change dramatically as Liszt incorporates support for distributed runtimes.
As an example, suppose we want to print both the velocity and pressure of a grid to the console with one line for each row.
cells:DumpJoint({'velocity', 'pressure'},
function(ids, v, p)
print(ids[1], ids[2], ': ', v[1], v[2], p)
end)
In order to support interoperability with external libraries (especially linear solvers) Liszt provides a way of requesting direct access to its underlying data storage. Data Layout Descriptors (DLDs) are meta-data describing this data layout.
However, client code and external libraries do not have any way to control how Liszt arranges its internal representations. As such, external code is required to either marshall/copy data into its own storage, or to adapt to however Liszt chooses to arrange memory.
field:getDLD()
This call returns a DLD describing the data layout of a field.
NOTE: The exact format of DLDs is preliminary and subject to change. The following describes the current convention.
dld.location
A string describing the location of the data (either 'CPU'
or 'GPU'
)
dld.type.dimensions
if the type is a scalar, this is an empty Lua list {}
; if the type is a vector this is a Lua list containing one number, the length of the vector {N}
; if the type is a matrix, this is a Lua list containing the dimensions {Nrow,Ncol}
.
dld.type.base_type_str
a string describing the C type of the field's base type
dld.type.base_bytes
a number giving the size of the base type in bytes
dld.logical_size
describes the number of items in the array, i.e. the number of rows
dld.address
a pointer to the beginning of the data
dld.stride
number, how many bytes to advance the pointer in order to find the next row's data
Liszt supports macros in the style of Terra as an advanced feature.
local m = L.Macro(lua_generator_function)
NewMacro
takes a Lua generator function as its argument. This function is passed Liszt ASTs as arguments and expected to return a Liszt AST as its result. For instance, the following macro implements addition.
local sum_macro = L.Macro(function(arg1, arg2)
return liszt `arg1 + arg2
end)
L.is_macro(obj)
Test whether a Lua object is a macro or not.
rel:NewFieldMacro(name, macro)
Install macro
with name name
on relation rel
as if it were a function. Inside Liszt code, whenever a key from rel
accesses name
, the macro will be expanded and passed the key as its only argument. A macro bound to the special name __apply_macro
will instead be expanded wherever a programmer calls a key from the relation, and passed the key along with any arguments as arguments to the macro function.
This feature allows us to expose more friendly syntax to the users of geometric domain libraries.
vertices:NewFieldMacro('edges', L.Macro(function(v)
return liszt `L.Where(edges.tail, v)
end))
This macro now allows client programmers to write for e in v.edges do ... end
when v
is a key from vertices
.
cells:NewFieldMacro('__apply_macro', L.Macro(function(c, xoff, yoff)
return liszt `L.Affine(cells, {{1, 0, xoff},
{0, 1, yoff}}, c)
end))
This macro now allows client programmers to write c(-1,2)
in order to access the neighbor of c
that's -1
away in the x direction and 2
away in the y direction.
Liszt functions can be declared similarly to Lua functions, except the keyword function
is replaced by liszt
.
liszt foo() ... end
local liszt foo() ... end
local foo = liszt() ... end
local namespace = {}
liszt namespace.foo() ... end
Arguments to Liszt functions can be optionally typed.
local liszt foo( a : L.vec3d, b : L.float ) ... end
local liszt bar( a : L.vec3d, b ) ... end
local liszt baz( a, b ) ... end
local liszt bop( c : cells ) ... end
local liszt fim( c )
When the Lua interpreter encounters the definition of a Liszt function, all Lua values used in the definition of the Liszt function are captured.
Then, when the function is used for the first time, Liszt will type-check the function. If the function is never used, but contains type-errors, none will be reported. Untyped functions are implicitly polymorphic. Liszt will create, typecheck and compile a separate version of each polymorphic function for each different type signature it's called with.
L.is_function(obj)
Test whether a Lua object is a Liszt function or not.
rel:NewFieldFunction(name, liszt_function)
Liszt functions can be installed on relations as if they were fields. Liszt expects liszt_function
to have exactly one argument of type L.key(rel)
, i.e. liszt_function( r : rel )
. Then, whenever a key from rel
is accessed as r.name
, that access will be replaced the call liszt_function(r)
. In this way, it's possible for Liszt programmers to easily replace fields of data with dynamically computed fields or vice-versa.
Liszt provides a number of built-in functions.
L.cos
L.sin
L.tan
L.acos
L.asin
L.atan
L.fmod
L.pow
L.sqrt
L.cbrt
L.floor
L.ceil
L.fabs
These standard mathematical functions are provided as built-ins. They will be replaced with GPU/CUDA intrinsics when code is run on the GPU, unlike the standard C math library.
L.cross(a,b)
L.dot(a,b)
L.length(a)
These functions work on Liszt vector values and are provided for convenience.
L.id(k)
L.xid(k)
L.yid(k)
L.zid(k)
These functions are provided to extract key identifiers. (L.uint64
values) If k
is from a Grid mode relation, then the xid
/yid
/zid
variants should be used; otherwise the id
variant should be used.
NOTE: the values returned from L.id()
are likely to change when Liszt starts supporting distributed runtimes.
L.assert( boolean_expression )
Terminate execution if the boolean expression evaluates to false
L.print(value1, [value2, ...])
Print some number of values to the console for debugging. No ordering guarantees are provided. Furthermore, since Liszt does not support string data, no formatting is currently allowed.


|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
Object org.apache.spark.mllib.linalg.DenseMatrix
public class DenseMatrix
Column-major dense matrix. The entry values are stored in a single array of doubles with columns listed in sequence. For example, the following matrix
1.0 2.0
3.0 4.0
5.0 6.0
is stored as [1.0, 3.0, 5.0, 2.0, 4.0, 6.0]
.
param: numRows number of rows
param: numCols number of columns
param: values matrix entries in column major if not transposed or in row major otherwise
param: isTransposed whether the matrix is transposed. If true, values
stores the matrix in
row major.
| Constructor Summary | |
|---|---|
DenseMatrix(int numRows,
int numCols,
double[] values)
Column-major dense matrix. |
|
DenseMatrix(int numRows,
int numCols,
double[] values,
boolean isTransposed)
|
| Method Summary | |
|---|---|
double |
apply(int i,
int j)
Gets the (i, j)-th element. |
DenseMatrix |
copy()
Get a deep copy of the matrix. |
static DenseMatrix |
diag(Vector vector)
Generate a diagonal matrix in DenseMatrix format from the supplied values. |
boolean |
equals(Object o)
|
static DenseMatrix |
eye(int n)
Generate an Identity Matrix in DenseMatrix format. |
int |
hashCode()
|
boolean |
isTransposed()
Flag that keeps track whether the matrix is transposed or not. |
int |
numCols()
Number of columns. |
int |
numRows()
Number of rows. |
static DenseMatrix |
ones(int numRows,
int numCols)
Generate a DenseMatrix consisting of ones. |
static DenseMatrix |
rand(int numRows,
int numCols,
java.util.Random rng)
Generate a DenseMatrix consisting of i.i.d. uniform random numbers. |
static DenseMatrix |
randn(int numRows,
int numCols,
java.util.Random rng)
Generate a DenseMatrix consisting of i.i.d. gaussian random numbers. |
SparseMatrix |
toSparse()
Generate a SparseMatrix from the given DenseMatrix . |
DenseMatrix |
transpose()
Transpose the Matrix. |
double[] |
values()
|
static DenseMatrix |
zeros(int numRows,
int numCols)
Generate a DenseMatrix consisting of zeros. |
| Methods inherited from class Object |
|---|
getClass, notify, notifyAll, toString, wait, wait, wait |
| Methods inherited from interface org.apache.spark.mllib.linalg.Matrix |
|---|
multiply, multiply, multiply, toArray, toString, toString |
| Constructor Detail |
|---|
public DenseMatrix(int numRows, int numCols, double[] values, boolean isTransposed)
public DenseMatrix(int numRows, int numCols, double[] values)
1.0 2.0
3.0 4.0
5.0 6.0
is stored as [1.0, 3.0, 5.0, 2.0, 4.0, 6.0]
.
numRows
- number of rowsnumCols
- number of columnsvalues
- matrix entries in column major| Method Detail |
|---|
public static DenseMatrix zeros(int numRows, int numCols)
DenseMatrix
consisting of zeros.
numRows
- number of rows of the matrixnumCols
- number of columns of the matrix
DenseMatrix
with size numRows
x numCols
and values of zerospublic static DenseMatrix ones(int numRows, int numCols)
DenseMatrix
consisting of ones.
numRows
- number of rows of the matrixnumCols
- number of columns of the matrix
DenseMatrix
with size numRows
x numCols
and values of onespublic static DenseMatrix eye(int n)
DenseMatrix
format.
n
- number of rows and columns of the matrix
DenseMatrix
with size n
x n
and values of ones on the diagonalpublic static DenseMatrix rand(int numRows, int numCols, java.util.Random rng)
DenseMatrix
consisting of i.i.d.
uniform random numbers.
numRows
- number of rows of the matrixnumCols
- number of columns of the matrixrng
- a random number generator
DenseMatrix
with size numRows
x numCols
and values in U(0, 1)public static DenseMatrix randn(int numRows, int numCols, java.util.Random rng)
DenseMatrix
consisting of i.i.d.
gaussian random numbers.
numRows
- number of rows of the matrixnumCols
- number of columns of the matrixrng
- a random number generator
DenseMatrix
with size numRows
x numCols
and values in N(0, 1)public static DenseMatrix diag(Vector vector)
DenseMatrix
format from the supplied values.
vector
- a Vector
that will form the values on the diagonal of the matrix
DenseMatrix
with size values.length
x values.length
and values
on the diagonalpublic int numRows()
Matrix
numRows
in interface Matrix
public int numCols()
Matrix
numCols
in interface Matrix
public double[] values()
public boolean isTransposed()
Matrix
isTransposed
in interface Matrix
public boolean equals(Object o)
equals
in class Object
public int hashCode()
hashCode
in class Object
public double apply(int i, int j)
Matrix
apply
in interface Matrix
public DenseMatrix copy()
Matrix
copy
in interface Matrix
public DenseMatrix transpose()
Matrix
transpose
in interface Matrix
public SparseMatrix toSparse()
SparseMatrix
from the given DenseMatrix
. The new matrix will have isTransposed
set to false.
|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |


Kozi internet is a flexible service that enables you to get reliable, fast and unlimited internet access from any of your desired location, either home or office.
How do I get access to Kozi internet?
Call<PHONE_NUMBER>, Our technicians will schedule a survey with you within 24 hours and there after organize for the installation.
How do i pay?
You can pay using our M-Pesa, to our paybill number 689177
What do I neeed to get access to the service?
Once you are connected you'll be given a Username and Password. You can use the details to connect to the internet on any device
How do I get assistance incase I have an issue or complaint?


Doping is a problem and alot of atheltes do it
The World Anti-Doping Agency has made it their mission to prevent unfair play, and promote a drug free sporting environment.
By supporting the WADA and their goals, we can promote a world of drug-free sport.


|
FlatBuffers
|
There's experimental support for reading FlatBuffers in Go. Generate code for Go with the -g
option to flatc
.
See go_test.go
for an example. You import the generated code, read a FlatBuffer binary file into a []byte
, which you pass to the GetRootAsMonster
function:
Now you can access values like this:
Note that whenever you access a new object like in the Pos
example above, a new temporary accessor object gets created. If your code is very performance sensitive (you iterate through a lot of objects), you can replace nil with a pointer to a Vec3
object you've already created. This allows you to reuse it across many calls and reduce the amount of object allocation (and thus garbage collection) your program does.
To access vectors you pass an extra index to the vector field accessor. Then a second method with the same name suffixed by Length
let's you know the number of elements you can access:
You can also construct these buffers in Go using the functions found in the generated code, and the FlatBufferBuilder class:
Create strings:
Create a table with a struct contained therein:
Unlike C++, Go does not support table creation functions like 'createMonster()'. This is to create the buffer without using temporary object allocation (since the Vec3
is an inline component of Monster
, it has to be created right where it is added, whereas the name and the inventory are not inline, and must be created outside of the table creation sequence). Structs do have convenient methods that allow you to construct them in one call. These also have arguments for nested structs, e.g. if a struct has a field a
and a nested struct field b
(which has fields c
and d
), then the arguments will be a
, c
and d
.
Vectors also use this start/end pattern to allow vectors of both scalar types and structs:
The generated method 'StartInventoryVector' is provided as a convenience function which calls 'StartVector' with the correct element size of the vector type which in this case is 'ubyte' or 1 byte per vector element. You pass the number of elements you want to write. You write the elements backwards since the buffer is being constructed back to front. You then pass inv
to the corresponding Add
call when you construct the table containing it afterwards.
There are Prepend
functions for all the scalar types. You use PrependUOffset
for any previously constructed objects (such as other tables, strings, vectors). For structs, you use the appropriate create
function in-line, as shown above in the Monster
example.
Once you're done constructing a buffer, you call Finish
with the root object offset (mon
in the example above). Your data now resides in Builder.Bytes. Important to note is that the real data starts at the index indicated by Head(), for Offset() bytes (this is because the buffer is constructed backwards). If you wanted to read the buffer right after creating it (using GetRootAsMonster
above), the second argument, instead of 0
would thus also be Head()
.
There currently is no support for parsing text (Schema's and JSON) directly from Go, though you could use the C++ parser through cgo. Please see the C++ documentation for more on text parsing.


... ! specify that an array "x_ray" is allocatable real, allocatable :: x_ray(:) ... ... ! allocate memory for the array allocate(x_ray(10)) ! use it do i=1,10 x_ray(i)=i+2 end do ! deallocate the array deallocate(x_ray)
module aptr REAL, POINTER, DIMENSION(:) :: VECTOR => NULL() !real, allocatable,target :: array(:) end module subroutine dummy(i) use aptr !save real, allocatable,target :: x_ray(:) write(*,*) write(*,*)"in dummy vector associated", ASSOCIATED(vector) ! write(*,*)allocated(x_ray) allocate(x_ray(i)) do j=1,i x_ray(j)=j enddo write(*,*)"vector associated", ASSOCIATED(vector), & " vector points to x_ray",ASSOCIATED(vector,x_ray) vector=>x_ray write(*,*)"vector associated", ASSOCIATED(vector), & " vector points to x_ray",ASSOCIATED(vector,x_ray) write(*,*)"sum(vector)",sum(vector),ASSOCIATED(vector) write(*,*) end subroutine program xyz use aptr write(*,*)"in main before first call to dummy" if(associated(vector)) then write(*,*)"sum(vector)",sum(vector),ASSOCIATED(vector) write(*,*)vector else write(*,*)"vector not ASSOCIATED" endif call dummy(5) write(*,*)"back in main after first call to dummy" if(associated(vector)) then write(*,*)"sum(vector)",sum(vector),ASSOCIATED(vector) write(*,*)vector else write(*,*)"vector not ASSOCIATED" endif call dummy(4) write(*,*)"back in main after second call to dummy" if(ASSOCIATED(vector)) then write(*,*)"sum(vector)",sum(vector),ASSOCIATED(vector) write(*,*)vector else write(*,*)"vector not ASSOCIATED" endif end
| Fortran 90 Complier - xlf90 | Fortran 95 Complier - xlf95 |
in main before first call to dummy vector not ASSOCIATED in dummy vector associated F vector associated F vector points to x_ray F vector associated T vector points to x_ray T sum(vector) 15.00000000 T back in main after first call to dummy sum(vector) 15.00000000 T 1.000000000 2.000000000 3.000000000 4.000000000 5.000000000 in dummy vector associated T vector associated T vector points to x_ray F vector associated T vector points to x_ray T sum(vector) 10.00000000 T back in main after second call to dummy sum(vector) 10.00000000 T 1.000000000 2.000000000 3.000000000 4.000000000 |
in main before first call to dummy vector not ASSOCIATED in dummy vector associated F vector associated F vector points to x_ray F vector associated T vector points to x_ray T sum(vector) 15.00000000 T back in main after first call to dummy sum(vector) 12.00000000 T 0.0000000000E+00 0.0000000000E+00 3.000000000 4.000000000 5.000000000 in dummy vector associated T vector associated T vector points to x_ray F vector associated T vector points to x_ray T sum(vector) 10.00000000 T back in main after second call to dummy sum(vector) 7.000000000 T 0.0000000000E+00 0.0000000000E+00 3.000000000 4.000000000 |
[tkaiser@mio001 tf]$ ls -lt fort.10 -rw-rw-r-- 1 tkaiser tkaiser 64 Jul 6 11:22 fort.10 [tkaiser@mio001 tf]$ cat fort.10 ?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@[tkaiser@mio001 tf]$ [tkaiser@mio001 tf]$ od -A d -j4 -v -N 64 -t f4 fort.10 0000004 4.000000e+00 4.000000e+00 4.000000e+00 4.000000e+00 0000020 4.000000e+00 4.000000e+00 4.000000e+00 4.000000e+00 0000036 4.000000e+00 4.000000e+00 4.000000e+00 4.000000e+00 0000052 4.000000e+00 4.000000e+00 4.000000e+00 0000064 [tkaiser@mio001 tf]$ od -A d -j4 -v -N 64 -b fort.10 0000004 000 000 200 100 000 000 200 100 000 000 200 100 000 000<PHONE_NUMBER>020 000 000 200 100 000 000 200 100 000 000 200 100 000 000<PHONE_NUMBER>036 000 000 200 100 000 000 200 100 000 000 200 100 000 000<PHONE_NUMBER>052 000 000 200 100 000 000 200 100 000 000<PHONE_NUMBER>064
[tkaiser@mio001 tf]$ cat fort.10 abcdefghABCDEFGHabcdefghABCDEFGHabcdefghABCDEFGHabcdefghABCDEFGH[tkaiser@mio001 tf]$ [tkaiser@mio001 tf]$ [tkaiser@mio001 tf]$ od -A d -j0 -v -N 64 -c fort.10 0000000 a b c d e f g h A B C D E F G H 0000016 a b c d e f g h A B C D E F G H 0000032 a b c d e f g h A B C D E F G H 0000048 a b c d e f g h A B C D E F G H
module numz ! module defines the basic real types integer, parameter:: b8 = selected_real_kind(14) integer, parameter:: b4 = selected_real_kind(3) integer, parameter :: in2 = selected_int_kind(1) integer, parameter :: in4 = selected_int_kind(6) integer, parameter :: in8 = selected_int_kind(12) end module function getlen(fname) integer i integer getlen character(len=1) :: a character(*) :: fname open(unit=11,file=trim(fname),form="unformatted",status="old",access="stream") len=0 do read(11,end=1234)a len=len+1 enddo 1234 continue close(11) getlen=len end function program atest use numz integer getlen real(b8) x8(4) real(b4) x4(8) integer(in2) i2(16) integer(in4) i4(8) integer(in8) i8(4) integer wrs,k character (len=8) str8 character (len=16) str16 character (len=1) str1(8) character (len=2) todo(10),indo wrs=0 do while(wrs < 10) read(*,*,end=1234)indo if(indo .eq. "st")goto 1234 wrs=wrs+1 todo(wrs)=indo enddo 1234 continue str8="!@#$%^&*" str16="abcdefghABCDEFGH" str1=(/"1","2","3","4","5","6","7","8"/) !write(*,*)str8 !write(*,*)str16 !write(*,*)str1 i2=(/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/) i4=(/10,20,30,40,50,60,70,80/) i8=(/100,200,300,400/) x8=(/10.,20.,30.,40./) x4=(/1.,2.,3.,4.,5.,6.,7.,8./) open(unit=9,file="fort.9",form="unformatted",status="replace") open(unit=10,file="fort.10",form="unformatted",status="replace",access="stream") do ifile=9,10 do i=1,wrs select case(todo(i)) case ("i2") write(ifile)i2 case ("i4") write(ifile)i4 case ("i8") write(ifile)i8 case ("r4") write(ifile)x4 case ("r8") write(ifile)x8 case ("c1") do k=1,4 write(ifile)str1 enddo case ("c8") do k=1,4 write(ifile)str8 enddo case ("cx") do k=1,2 write(ifile)str16 enddo end select enddo close(ifile) enddo open(unit=9,file="fort.9",form="unformatted",status="old") open(unit=10,file="fort.10",form="unformatted",status="old",access="stream") do ifile=9,10 do i=1,wrs select case(todo(i)) case ("i2") read(ifile)i2 ; write(*,*)i2 case ("i4") read(ifile)i4 ; write(*,*)i4 case ("i8") read(ifile)i8 ; write(*,*)i8 case ("r4") read(ifile)x4 ; write(*,*)x4 case ("r8") read(ifile)x8 ; write(*,*)x8 case ("c1") do k=1,4 read(ifile)str1 enddo write(*,*)str1 case ("c8") do k=1,4 read(ifile)str8 enddo write(*,*)str8 case ("cx") do k=1,2 read(ifile)str16 enddo write(*,*)str16 end select enddo close(ifile) enddo write(*,*) write(*,*)"length fort.10 =",getlen("fort.10") write(*,*)"length fort.9 =",getlen("fort.9") end program
open(unit=9, file="fort.9", form="unformatted",status="replace") open(unit=10,file="fort.10",form="unformatted",status="replace",access="stream")
[tkaiser@mio001 tf]$ ./a.out [tkaiser@mio001 tf]$ ./a.out r4 r4 st 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 length fort.10 = 64 length fort.9 = 80 [tkaiser@mio001 tf]$ [tkaiser@mio001 tf]$ ls -l fort.10 fort.9 -rw-rw-r-- 1 tkaiser tkaiser 32 Jul 6 13:05 fort.10 -rw-rw-r-- 1 tkaiser tkaiser 48 Jul 6 13:05 fort.9 [tkaiser@mio001 tf]$
[tkaiser@mio001 tf]$ ls -l fort.10 fort.9 -rw-rw-r-- 1 tkaiser tkaiser 32 Jul 6 13:05 fort.10 -rw-rw-r-- 1 tkaiser tkaiser 48 Jul 6 13:05 fort.9 [tkaiser@mio001 tf]$
| [tkaiser@mio001 tf]$ od -A d -v -b fort.10 | [tkaiser@mio001 tf]$ od -A d -v -b fort.9 |
0000000 000 000 200 077 000 000 000 100 000 000 100 100 000 000<PHONE_NUMBER>016 000 000 240 100 000 000 300 100 000 000 340 100 000 000<PHONE_NUMBER>032 000 000 200 077 000 000 000 100 000 000 100 100 000 000<PHONE_NUMBER>048 000 000 240 100 000 000 300 100 000 000 340 100 000 000<PHONE_NUMBER>064 [tkaiser@mio001 tf]$ |
0000000 040 000 000 000 000 000 200 077 000 000 000 100 000 000<PHONE_NUMBER>016 000 000 200 100 000 000 240 100 000 000 300 100 000 000<PHONE_NUMBER>032 000 000 000 101 040 000 000 000 040 000 000 000 000 000<PHONE_NUMBER>048 000 000 000 100 000 000 100 100 000 000 200 100 000 000<PHONE_NUMBER>064 000 000 300 100 000 000 340 100 000 000 000 101 040 000<PHONE_NUMBER>080 [tkaiser@mio001 tf]$ |
| [tkaiser@mio001 tf]$ od -A d -v -t f4 fort.10 | [tkaiser@mio001 tf]$ od -A d -v -t f4 fort.9 |
0000000 1.000000e+00 2.000000e+00 3.000000e+00 4.000000e+00 0000016 5.000000e+00 6.000000e+00 7.000000e+00 8.000000e+00 0000032 1.000000e+00 2.000000e+00 3.000000e+00 4.000000e+00 0000048 5.000000e+00 6.000000e+00 7.000000e+00 8.000000e+00 0000064 |
0000000 4.484155e-44 1.000000e+00 2.000000e+00 3.000000e+00 0000016 4.000000e+00 5.000000e+00 6.000000e+00 7.000000e+00 0000032 8.000000e+00 4.484155e-44 4.484155e-44 1.000000e+00 0000048 2.000000e+00 3.000000e+00 4.000000e+00 5.000000e+00 0000064 6.000000e+00 7.000000e+00 8.000000e+00 4.484155e-44 0000080 |
Since Fortran 2003 (ISO/IEC 1539-1:2004(E)) there is a standardized way to generate procedure and derived-type declarations and global variables which are interoperable with C (ISO/IEC 9899:1999).
Fortran 2003 adds a data type attribute bind(c), and a module, ISO_C_BINDING which standardizes Fortran/C ISO_C_BINDING.
| Name | C definition | Value |
|---|---|---|
| C_NULL_CHAR | null character | '\0' |
| C_ALERT | alert | '\a' |
| C_BACKSPACE | backspace | '\b' |
| C_FORM_FEED | form feed | '\f' |
| C_NEW_LINE | new line | '\n' |
| C_CARRIAGE_RETURN | carriage return | '\r' |
| C_HORIZONTAL_TAB | horizontal tab | '\t' |
| C_VERTICAL_TAB | vertical tab | '\v' |
We'll see examples of C_NULL_CHAR. It's important.
We'll look at C_LOC, C_F_POINTER and C_ASSOCIATED
The Fortran data types "map" to C types. If you want to use a variable in both Fortran and C it should be declared as one of thes types in Fortran.
| Fortran Type | Named constant | C type |
|---|---|---|
| INTEGER | C_INT | int |
| INTEGER | C_SHORT | short int |
| INTEGER | C_LONG | long int |
| INTEGER | C_LONG_LONG | long long int |
| INTEGER | C_SIGNED_CHAR | signed char/unsigned char |
| INTEGER | C_SIZE_T | size_t |
| INTEGER | C_INT8_T | int8_t |
| INTEGER | C_INT16_T | int16_t |
| INTEGER | C_INT32_T | int32_t |
| INTEGER | C_INT64_T | int64_t |
| INTEGER | C_INT_LEAST8_T | int_least8_t |
| INTEGER | C_INT_LEAST16_T | int_least16_t |
| INTEGER | C_INT_LEAST32_T | int_least32_t |
| INTEGER | C_INT_LEAST64_T | int_least64_t |
| INTEGER | C_INT_FAST8_T | int_fast8_t |
| INTEGER | C_INT_FAST16_T | int_fast16_t |
| INTEGER | C_INT_FAST32_T | int_fast32_t |
| INTEGER | C_INT_FAST64_T | int_fast64_t |
| INTEGER | C_INTMAX_T | intmax_t |
| INTEGER | C_INTPTR_T | intptr_t |
| REAL | C_FLOAT | float |
| REAL | C_DOUBLE | double |
| REAL | C_LONG_DOUBLE | long double |
| COMPLEX | C_FLOAT_COMPLEX | float _Complex |
| COMPLEX | C_DOUBLE_COMPLEX | double _Complex |
| COMPLEX | C_LONG_DOUBLE_COMPLEX | long double _Complex |
| LOGICAL | C_BOOL | _Bool |
| CHARACTER | C_CHAR | char |
write(*,*)"length fort.10 =",getlen_c("fort.10") write(*,*)"length fort.9 =",getlen_c("fort.9")
#include
#include
#include
#include
size_t c_filesize(char* filename)
{
size_t rv = 0; // Return 0, if failure
struct stat file_info;
if ( (filename != NULL) && (stat(filename,&file_info) == 0) ) //NULL check/stat() call
rv = (size_t)file_info.st_size; // Note: this may not fit in a size_t variable
return rv;
}
|
Our Function getlen_c takes a file name and returns a file length. ISO_C_BINDING contains our Fortran equivalent data types. Here we are going to define variables that have typed matching C long and C char. We are also going to use the C null character. Our function returns an integer of type "in8". In8 is defined in "numz" to be an 8 byte integer. Next we have the interface for our C routine. It will return a C long and take a C character array. The BIND clause first "just" says that this is a C routine. If you have ever written mixed language programs you will appreciate the NAME='c_filesize' clause. What this does is specify the name of the routine in C. Why is this important. Previously, if you wrote a mixed language program the Fortran compiler may or may not append and underscore (_) to the end of the routine name. So on the C side you would need to be able to compile with or without the underscore. Here we are forcing the Fortran compiler to name our C function as given. The string we are sending to the C routine is defined here. We are going to fill it with NULLs. This is a bit of an overkill. Only the character after our filename needs to be NULL. Next we "unpad" our input string and copy it to our C string. Finally we call the C routine. |
Source: fandc.f90 - moduleMODULE FTN_C
INTERFACE
! int C_Library_Function(float* sendbuf, int sendcount, float *recvcounts, float *mysum)
INTEGER (C_INT) FUNCTION C_LIBRARY_FUNCTION (SENDBUF, SENDCOUNT, RECV, mysum) &
BIND(C, NAME='C_Library_Function')
USE ISO_C_BINDING
IMPLICIT NONE
TYPE (C_PTR), VALUE :: SENDBUF
INTEGER (C_INT), VALUE :: SENDCOUNT
Real (C_FLOAT) :: mysum
TYPE (C_PTR), VALUE :: RECV
END FUNCTION C_LIBRARY_FUNCTION
END INTERFACE
INTERFACE
subroutine c_dosim ( ) BIND(C, NAME='do_sim')
USE ISO_C_BINDING
IMPLICIT NONE
END subroutine c_dosim
END INTERFACE
END MODULE FTN_C
Source: fandc.f90 - main program backforth
USE ISO_C_BINDING, ONLY: C_INT, C_FLOAT, C_LOC
USE FTN_C
REAL (C_FLOAT), TARGET :: SEND(10)
INTEGER (C_INT) :: SENDCOUNT
Real (C_FLOAT) :: mysum
REAL (C_FLOAT), ALLOCATABLE, TARGET :: RECV(:)
SENDCOUNT=size(SEND)
do i=1,SENDCOUNT
SEND(i)=i
enddo
ALLOCATE( RECV(SENDCOUNT) )
mysum=-1.0
write(*,'("Fortran mysum before C call = ",f7.1)'),mysum
i=C_LIBRARY_FUNCTION(C_LOC(SEND), SENDCOUNT, C_LOC(RECV),mysum)
write(*,'("Back from C in Fortran mysum = ",f7.1)'),mysum
do i=1,SENDCOUNT
write(*,*)send(i),recv(i)
enddo
write(*,'("Fortran calling C again")')
call c_dosim()
end program
Source: fandc.f90 - subroutineSUBROUTINE SIMULATION(ALPHA, BETA, GAMMA, DELTA, ARRAYS) BIND(C ,NAME='f_routine')
USE ISO_C_BINDING
IMPLICIT NONE
INTEGER (C_LONG), VALUE :: alpha
REAL (C_DOUBLE), INTENT(INOUT) :: beta
REAL (C_DOUBLE), INTENT(OUT) :: gamma
REAL (C_DOUBLE),DIMENSION(*),INTENT(IN) :: DELTA
TYPE, BIND(C) :: PASS
INTEGER (C_INT) :: LENC, LENF
TYPE (C_PTR) :: C, F
END TYPE PASS
TYPE (PASS), INTENT(INOUT) :: ARRAYS
REAL (C_FLOAT), ALLOCATABLE, TARGET, SAVE :: ETA(:)
REAL (C_FLOAT), POINTER :: C_ARRAY(:)
integer i,j
write(*,'("In Fortran called from C alpha=",i4,&
" beta=",f10.2," gamma=",f10.2)')&
alpha,beta,gamma
gamma=0.0
do i=1,alpha
gamma=gamma+beta*delta(i)
enddo
beta=1234.0
!...
write(*,*)"! Associate C_ARRAY with an array allocated in C"
CALL C_F_POINTER (ARRAYS%C, C_ARRAY, (/ARRAYS%LENC/) )
if(c_associated(ARRAYS%C, c_loc(C_ARRAY)))then
write(*,*)'ARRAYS%C, C_ARRAY point to same target'
else
write(*,*)'ARRAYS%C, C_ARRAY do not point to same target'
stop
endif
!...
write(*,*)"! Allocate an array and make it available in C"
ARRAYS%LENF = 100
ALLOCATE (ETA(ARRAYS%LENF))
ARRAYS%F = C_LOC(ETA)
j=min(ARRAYS%lenc,ARRAYS%lenf)
write(*,*)"Fortan fills the array for C"
do i=1,j
ETA(i)=C_ARRAY(i)*2
enddo
END SUBROUTINE SIMULATION
MODULE FTN_C INTERFACE ! int C_Library_Function(float* sendbuf, int sendcount, float *recvcounts, float *mysum) INTEGER (C_INT) FUNCTION C_LIBRARY_FUNCTION (SENDBUF, SENDCOUNT, RECV, mysum) & BIND(C, NAME='C_Library_Function') USE ISO_C_BINDING IMPLICIT NONE TYPE (C_PTR), VALUE :: SENDBUF INTEGER (C_INT), VALUE :: SENDCOUNT Real (C_FLOAT) :: mysum TYPE (C_PTR), VALUE :: RECV END FUNCTION C_LIBRARY_FUNCTION END INTERFACE INTERFACE subroutine c_dosim ( ) BIND(C, NAME='do_sim') USE ISO_C_BINDING IMPLICIT NONE END subroutine c_dosim END INTERFACE END MODULE FTN_C SUBROUTINE SIMULATION(ALPHA, BETA, GAMMA, DELTA, ARRAYS) BIND(C ,NAME='f_routine') USE ISO_C_BINDING IMPLICIT NONE INTEGER (C_LONG), VALUE :: alpha REAL (C_DOUBLE), INTENT(INOUT) :: beta REAL (C_DOUBLE), INTENT(OUT) :: gamma REAL (C_DOUBLE),DIMENSION(*),INTENT(IN) :: DELTA TYPE, BIND(C) :: PASS INTEGER (C_INT) :: LENC, LENF TYPE (C_PTR) :: C, F END TYPE PASS TYPE (PASS), INTENT(INOUT) :: ARRAYS REAL (C_FLOAT), ALLOCATABLE, TARGET, SAVE :: ETA(:) REAL (C_FLOAT), POINTER :: C_ARRAY(:) integer i,j write(*,'("In Fortran called from C alpha=",i4,& " beta=",f10.2," gamma=",f10.2)')& alpha,beta,gamma gamma=0.0 do i=1,alpha gamma=gamma+beta*delta(i) enddo beta=1234.0 !... write(*,*)"! Associate C_ARRAY with an array allocated in C" CALL C_F_POINTER (ARRAYS%C, C_ARRAY, (/ARRAYS%LENC/) ) if(c_associated(ARRAYS%C, c_loc(C_ARRAY)))then write(*,*)'ARRAYS%C, C_ARRAY point to same target' else write(*,*)'ARRAYS%C, C_ARRAY do not point to same target' stop endif !... write(*,*)"! Allocate an array and make it available in C" ARRAYS%LENF = 100 ALLOCATE (ETA(ARRAYS%LENF)) ARRAYS%F = C_LOC(ETA) j=min(ARRAYS%lenc,ARRAYS%lenf) write(*,*)"Fortan fills the array for C" do i=1,j ETA(i)=C_ARRAY(i)*2 enddo END SUBROUTINE SIMULATION program backforth USE ISO_C_BINDING, ONLY: C_INT, C_FLOAT, C_LOC USE FTN_C REAL (C_FLOAT), TARGET :: SEND(10) INTEGER (C_INT) :: SENDCOUNT Real (C_FLOAT) :: mysum REAL (C_FLOAT), ALLOCATABLE, TARGET :: RECV(:) SENDCOUNT=size(SEND) do i=1,SENDCOUNT SEND(i)=i enddo ALLOCATE( RECV(SENDCOUNT) ) mysum=-1.0 write(*,'("Fortran mysum before C call = ",f7.1)'),mysum i=C_LIBRARY_FUNCTION(C_LOC(SEND), SENDCOUNT, C_LOC(RECV),mysum) write(*,'("Back from C in Fortran mysum = ",f7.1)'),mysum do i=1,SENDCOUNT write(*,*)send(i),recv(i) enddo write(*,'("Fortran calling C again")') call c_dosim() end program
program backforth USE ISO_C_BINDING, ONLY: C_INT, C_FLOAT, C_LOC USE FTN_C REAL (C_FLOAT), TARGET :: SEND(10) INTEGER (C_INT) :: SENDCOUNT Real (C_FLOAT) :: mysum REAL (C_FLOAT), ALLOCATABLE, TARGET :: RECV(:) SENDCOUNT=size(SEND) do i=1,SENDCOUNT SEND(i)=i enddo ALLOCATE( RECV(SENDCOUNT) ) mysum=-1.0 write(*,'("Fortran mysum before C call = ",f7.1)'),mysum i=C_LIBRARY_FUNCTION(C_LOC(SEND), SENDCOUNT, C_LOC(RECV),mysum) write(*,'("Back from C in Fortran mysum = ",f7.1)'),mysum do i=1,SENDCOUNT write(*,*)send(i),recv(i) enddo write(*,'("Fortran calling C again")') call c_dosim() end program |
We will use C ints and floats in this program as well as the C_LOC function so there are included here. We will be sending a regular array which we fill. We allocate an array that will have data put in it in the C procedure. MYSUM will also be modified in the c routine. SENDCOUNT will not be changed. Using C_LOC is a bit odd in my opinion. SEND and RECV are arrays but we will be sending the arrays as pointers. C_LOC gives the pointer address. We next look at the interface for C_LIBRARY_FUNCTION. Before that we note that after the call to C_LIBRARY_FUNCTION we print our returned data. |
Our InterfaceMODULE FTN_C INTERFACE ! int C_Library_Function(float* sendbuf, int sendcount, float *recvcounts, float *mysum) INTEGER (C_INT) FUNCTION C_LIBRARY_FUNCTION (SENDBUF, SENDCOUNT, RECV, mysum) & BIND(C, NAME='C_Library_Function') USE ISO_C_BINDING IMPLICIT NONE TYPE (C_PTR), VALUE :: SENDBUF INTEGER (C_INT), VALUE :: SENDCOUNT Real (C_FLOAT) :: mysum TYPE (C_PTR), VALUE :: RECV END FUNCTION C_LIBRARY_FUNCTION END INTERFACE INTERFACE subroutine c_dosim ( ) BIND(C, NAME='do_sim') USE ISO_C_BINDING IMPLICIT NONE END subroutine c_dosim END INTERFACE END MODULE FTN_C |
We include the C interface for the routine as a reference. In the interface we declare the SENDBUF and RECV as pointers. So this matches what we did in the program. Note that we are sending these by VALUE, which is normal for C. We can do this because we are not changing the value of the pointer. SENDCOUNT will not change either so we send by value. MYSUM will be changed in the C routine. It is sent by location. Note in the C routine it will be dereferenced as indicated in the C interface. |
#include |
The Routine just takes the input array and put sin in the output array and sums into *mysum. The cool thing about this routine is that there is nothing special about it. Note: sendbuf, recvcounts, are pointers / arrays. We are passing back mysum so it also needs to be a pointer. Finally sendcount is not a pointer because it is not changed. |
#include |
We have a data structure that will have a match in Fortran This interface statement is for our Fortran Routine We set alpha, beta, gamma, allocate delta and fill it. The "len" portions of our data structure are assigned. We allocate arrays.c and fill it but we don't allocate arrays.f We call our Fortran routine. On return from Fortran beta and gamma have been changed and arrays.f has been allocated and filled. |
SUBROUTINE SIMULATION(ALPHA, BETA, GAMMA, DELTA, ARRAYS) BIND(C ,NAME='f_routine') USE ISO_C_BINDING IMPLICIT NONE INTEGER (C_LONG), VALUE :: alpha REAL (C_DOUBLE), INTENT(INOUT) :: beta REAL (C_DOUBLE), INTENT(OUT) :: gamma REAL (C_DOUBLE),DIMENSION(*),INTENT(IN) :: DELTA TYPE, BIND(C) :: PASS INTEGER (C_INT) :: LENC, LENF TYPE (C_PTR) :: C, F END TYPE PASS TYPE (PASS), INTENT(INOUT) :: ARRAYS REAL (C_FLOAT), ALLOCATABLE, TARGET, SAVE :: ETA(:) REAL (C_FLOAT), POINTER :: C_ARRAY(:) integer i,j write(*,'("In Fortran called from C alpha=",i4,& " beta=",f10.2," gamma=",f10.2)')& alpha,beta,gamma gamma=0.0 do i=1,alpha gamma=gamma+beta*delta(i) enddo beta=1234.0 !... write(*,*)"! Associate C_ARRAY with an array allocated in C" CALL C_F_POINTER (ARRAYS%C, C_ARRAY, (/ARRAYS%LENC/) ) if(c_associated(ARRAYS%C, c_loc(C_ARRAY)))then write(*,*)'ARRAYS%C, C_ARRAY point to same target' else write(*,*)'ARRAYS%C, C_ARRAY do not point to same target' stop endif !... write(*,*)"! Allocate an array and make it available in C" ARRAYS%LENF = 100 ALLOCATE (ETA(ARRAYS%LENF)) ARRAYS%F = C_LOC(ETA) j=min(ARRAYS%lenc,ARRAYS%lenf) write(*,*)"Fortan fills the array for C" do i=1,j ETA(i)=C_ARRAY(i)*2 enddo END SUBROUTINE SIMULATION |
The subroutine statement says that this routine can be called from C with the name f_routine Alpha is passed by value as indicated by the attribute. Beta has intent inout and gamma out. Both could have been given intent inout since they are passed as pointers. Next we have our data structure arrays having the type pass matching the C pass structure. We finally have eta and c_array which will be mapped to arrays in the C world. We are changing beta and gamma. These changed values gets printed in C. We are passing in our data structure which contains ARRAYS%C. We show here haw we can use C_F_POINTER to set a pointer to that. Then we call c_associated to check that this worked. Next we show how we can allocate an array in Fortran "ETA" and then assign its memory to the array originally from C. This is done indirectly, we don't allocate the C variable. The reason for this is related to what we talked about earlier. The array could be automatically deallocated on routine exit. Here we give "ETA" the save attribute to prevent that. |
In C mysum before loop =-1 In C mysum after loop = 4.5 C in do_sim Fortran mysum before C call = -1.0 Back from C in Fortran mysum = 4.5 1.00000000 0.00000000 2.00000000 0.642787576 3.00000000 0.984807730 4.00000000 0.866025448 5.00000000 0.342020273 6.00000000 -0.342019975 7.00000000 -0.866025329 8.00000000 -0.984807789 9.00000000 -0.642787814 10.0000000 -3.01991605E-07 Fortran calling C again In Fortran called from C alpha= 10 beta= 0.50 gamma= 0.00 ! Associate C_ARRAY with an array allocated in C ARRAYS%C, C_ARRAY point to same target ! Allocate an array and make it available in C Fortan fills the array for C C back in do_sim beta = 1234 gamma=2250 0 0 1 2 2 4 3 6 4 8 5 10 6 12 7 14 8 16 9 18
Fortran 95 provides an efficient alternative to the element by element construction of an array value in Fortran 90.
| Fortran 90 nested Do | Similar Fortran 95 Forall |
|---|---|
do j=j1,j2
do i=i1,i2
new_psi(i,j)=a1*psi(i+1,j) + a2*psi(i-1,j) + &
a3*psi(i,j+1) + a4*psi(i,j-1) - &
a5*for(i,j)
enddo
enddo
psi(i1:i2,j1:j2)=new_psi(i1:i2,j1:j2)
|
FORALL (i=i1:i2, j=j1:j2)
psi(i,j)=a1*psi(i+1,j) + a2*psi(i-1,j) + &
a3*psi(i,j+1) + a4*psi(i,j-1) - &
a5*for(i,j)
end forall
|
| run time = 7.08 (75,000 iterations) | run time = 6.58 (75,000 iterations) |
Source: list.f90 - moduleClick to open this file in a new window.
Source: link.f90 - moduleClick to open this file in a new window.
Source: ll.f90 - moduleClick to open this file in a new window.
| Source | Output |
program main use list_mod implicit none integer i type(list) :: my_list do i=1, 10 call my_list%add(i) enddo call my_list%add(1.23) call my_list%add('A') call my_list%add('B') call my_list%add('C') call my_list%printvalues() end program main |
1 2 3 4 5 6 7 8 9 10 1.23000002 A B C |


As a {{requirement.actor}}, I want {{ requirement.function}} so that {{ requirement.outcome }}.
code palette build {{ task.description }}


Context:
{context}
{response}
Please rate how likely the response continues from the conversation above.