1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
|
.. _cpp_reminder:
C++ Refresher
=============
C++ is the basic language of Siconos input files, thus you need at least a basic knowledge of C++.
This topic is covered by many books or tutorials, try for example :cite:`eckel_cpp`.
However, you can find in this first section the main C++ commands you need to know to write a first input file.
This page presents some basic commands and things you need to know to write a first C++ driver for your simulation.
Note: In recent versions it is possible to design complete Siconos
simulations using the Python programming language. If you are
using the Python interface, most of this document can be ignored.
However, the Python interface uses the same class names. See the
:ref:`siconos_python_reference`.
Building/destroying and using objects
-------------------------------------
.. highlight:: c++
To describe your problem, you will mainly need to build pointers to objects.
Siconos use smart pointers so you do not have to bother with deletion.
The namespace SP enclose typedefs of all Siconos classes as smart pointers.
So to build an object of class *CHILD* derived from base class *BASE*, the syntax will be::
SP::BASE my_object_name(new CHILD(some args ...)
For example, suppose you want to build a LagrangianDS, which belongs
to the base class DynamicalSystem, then do::
SP::DynamicalSystem nameOfMyDS(new LagrangianDS(someParameters));
*new* call will reserve memory and build the object.
For each object, different types of constructors may be available. For an
exhaustive list see :ref:`siconos_api_reference`.
Members/Methods access
----------------------
The access to the methods of the objects is done thanks to "*" or "->"::
nameOfMyDS->getType(); // return the type of the DynamicalSystem
(*nameOfMyDS).getType(); // Same thing.
Matrices and vectors handling
-----------------------------
The basic classes available in the platform to deal with vectors and matrices are:
* :class:`SiconosVector` : vector of double, can be dense or sparse.
* :class:`BlockVector` : vector of :class:`SiconosVector`
* :class:`SimpleMatrix` : matrix of double, can be dense, sparse, triangular, banded, symmetric, zero or identity.
* :class:`BlockMatrix` : matrix of :class:`SimpleMatrix`
All these objects are just an interface to `Boost Ublas library <http://www.boost.org/libs/numeric/ublas/doc/index.htm>`_ vector and matrix.
Notice that BlockVector or BlockMatrix are no more that a collection of pointers to SiconosVector or SimpleMatrix.
Then in most cases, to build such an object, you just need to insert some existing objects.
The usual ways of construction are described below.
::
# build a dense vector of 4 elements
SP::SiconosVector v1(new SimpleVector(4));
# build a sparse vector of size 4
SP::SiconosVector vsparse(new SimpleVector(4, Siconos::SPARSE)
# build a block vector, which contains 3 dense blocks of size 5
SP::BlockVector vblock(new BlockVector(3, 5));
# build a block vector, which contains 2 sparse
SP::SiconosVector v2(new SiconosVector(4, Siconos::SPARSE)
SP::SiconosVector v3(new SiconosVector(7, Siconos::SPARSE)
SP::BlockVector vblock(new BlockVector(v2, v3));
int row = 3, col = 3;
// row X col Dense matrix:
SP::SiconosMatrix m(new SimpleMatrix(row,col));
// row X col matrix, all elements initialized with a scalar value:
double a = 4.4;
SP::SiconosMatrix m(new SimpleMatrix(row,col,a));
// row X row Symmetric matrix:
SP::SiconosMatrix m(new SimpleMatrix(row,row, Siconos::SYMMETRIC));
// Read from a file
SP::SiconosMatrix m2(new SimpleMatrix("mat.dat",1)); // 1: ascii, 0:binary
// Build an empty vector and insert some existing vectors.
SP::BlockVector V0(new BlockVector());
// Pointer insertion:
V0->insertPtr(v1);
// V0 has now one block equal to v1.
// warning: because of pointer equality,
// v1 and (*V0)[0] represent the same object
// and thus have the same memory location.
// Copy of an existing vector:
V0->insert(*v2);
// A new block has been created in V0
// and v2 has been copied into this block.
// Thus v2 and (*V0)[1] contain the same
// elements but are two different objects.
Note that a BlockVector can also contain some other BlockVector::
SP::BlockVector V1(new BlockVector());
V1->insertPtr(V0);
V1->insertPtr(v1);
V1 has now two blocks: the first one is a block of two blocks and the second is equal to v1.
::
// m1 ... m4 some SP::SiconosMatrix
SP::SiconosMatrix M(new BlockMatrix(m1,m2,m3,m4));
// M is a 2X2 blocks matrix
// (first row: m1, m2, second: m3, m4).
Keywords for constructors, in Siconos namespace: DENSE (default), TRIANGULAR, SYMMETRIC, SPARSE, BANDED, ZERO, IDENTITY.
Check the complete list of available constructors in reference documentation of each class.
Read/write vectors and matrices from/to file
""""""""""""""""""""""""""""""""""""""""""""
This is done using :class:`ioVector` and :class:`ioMatrix` classes.
::
// Read/write vector/matrix from/to file
// v is a vector, m a matrix
ioVector myOutput ("MyData","ascii");
myOutput.read(v); // read v from file MyData
ioMatrix myMat("outMat","ascii");
myMat.write(m); // Write m in file outMat
Input/Ouput Files format:
On the first line, the dimensions, with space as separator. Then the data.
Example, for a 2-rows, 3-columns matrix:
::
2 3
1 2 3
4 5 6
However, if you give as a second argument to write function "noDim", the first line with dimensions will not be written.
Methods and operations on matrices and vectors
""""""""""""""""""""""""""""""""""""""""""""""
Important note: in many of the operators described below, a boolean argument "init" can be set. If equal to true (default value) then the operator used "=" and if set to
false, "+=".
::
v->size() // return the size of the vector
m->size(0); // number of rows in the matrix
m->size(1), // number of columns
m->resize(a,b); // resize m, available also for vectors
// To compute C = A*B
prod(A,B,C,true);
// or
prod(A,B,C);
// To compute C += A*B
prod(A,B,C,false);
//Single elements access or assignment: operator "()" or \e get/setValue functions.
SP::SiconosVector v(new SimpleVector(3)); // v = [0 0 0]
SimpleVector w(4); // w = [0 0 0 0]
(*v)(0) = 4; // v = [4 0 0]
// equivalent to:
v->setValue(0,4);
w(1) = 2;
w(2) = (*v)(0); // w = [0 2 4 0]
// equivalent to:
w.setValue( 2,v->getValue(0) );
SP::SiconosMatrix M(new SimpleMatrix(3,3)); // M = [ 0 0 0 ]
// [ 0 0 0 ]
// [ 0 0 0 ]
SimpleMatrix P(1,2); // P = [ 0 0 ]
(*M)(1,2) = 2;
P(0,1) = 12; // P = [ 0 12.0 ]
M->setValue(2,0,3.6); // M = [ 0 0 0 ]
// [ 0 0 2.0 ]
// [ 3.6 0 0 ]
cout << P.getValue(0,1); // display 12.0
Note: for sparse matrices, assignment with operator "()" fails. It is then necessary to use setValue function.
::
SP::SiconosMatrix A(new SimpleMatrix(10,10,SPARSE));
(*A)(0,0) = 12; // WRONG
A->setValue(0,0,12); // OK
For BlockVector: "()" and get/setValue functions have the same action as for SimpleVectors::
// We suppose that v1 and v2 are two pointers to SimpleVector of size 3 and 4.
SP::SiconosVector vB(new BlockVector(v1,v2)); // vB = [ [1 2 3] [4 5 6 7] ]
(*vB)(4) = 12; // vB = [ [1 2 3] [4 12 6 7] ]
vB->setValue(6,8.6); // vB = [ [1 2 3] [4 12 6 8.6] ]
// Warning: the given input for position is an "absolute" one, not a block position.
Remark: get/setValue functions are equivalent to "()" operator but mainly useful in Siconos-Python, since in that case operators can not be overloaded and thus
"()" is not available. The same remark applies for "[ ]" get/setVector and in a general way for all operators overloading.
::
// Set vector or matrix to zero or identity
x->zero();
A->zero();
A->eye();
// Assignment of vectors or matrices: "A = B" or "x = y"
// Operator =
// Ok if A and x have been built before.
A = B;
x = y;
// Remark: sizes must be consistents between A/B and x/y,
// else it results in a Siconos Exception.
// Else copy constructor: memory allocation and initialization with B or x
SP::SiconosMatrix A(new SimpleMatrix(*B));
SP::SiconosVector x(new SimpleVector(*y));
// Addition of matrices or vectors
// add "in place": A = A+B or x = x+y
A += B;
x += y;
C = A+B;
add(A,B,C);
A -= B;
C = A-B;
sub(A,B,C);
// Multiplication by a scalar:
A *=a;
B = a*A;
scal(a,A,B);
A /=a;
x /=a;
B = A/a;
scal(1.0/a,A,B);
// matrices product
C = A*B;
prod(A,B,C);
// C and A or B can be the same matrices (ie have common memory),
// but that will slow down the operation.
gemm(A,B,C); // Only for denses matrices.
// It is also possible to compute product of sub-blocks of matrices or vectors:
// Declare A, x, y ...
//
std::vector<unsigned int> coord;
// Set coord values ...
bool init = false;
subprod(A,x,y,coord,init);
Coord vector is equal to [r0A, r1A,, c0A, c1A, r0x, r1x, r0y, r1y]. The sub-matrix A is the matrix between row positions
r0A and r1A, column position between c0A and c1A. Same thing for x and y with rix, riy.
Then subprod computes suby = subA*subx if init = true, or suby += subA*subx if init = false.
::
Matrix transpose:
// in place:
A->trans();
// B = At
B->trans(A);
// inner product: a = x.y
a = inner_prod(x,y);
// Matrix-vector product: \f$y=A*x\f$
y = prod(A,x);
prod(A,x,y);
To handle a specific block, use "[ ]" or getVector and getVectorPtr functions::
SP::SiconosVector v3(new SimpleVector(3)); // v3 = [0 0 0]
SP::SiconosVector v4(new SimpleVector(4)); // v4 = [0 0 0 0]
// get and copy a block:
*v3 = *(*vB[0]); // v3 = v1 = [1 2 3]
// Equivalent to
*v3 = *vB->getVectorPtr(0);
// get and copy pointer to block:
v4 = vB->getVectorPtr(1); // v4 = v2 = [4 12 6 8.6]
// AND pointer equality
// between v4, vB[1] and v2
// Equivalent to:
v4 = (*vB)[1]; // v4 = v2 = [4 12 6 8.6].
// Assignment:
SP::SiconosVector v5(new SimpleVector(3)); // v5 = [0 0 0]
*(*vB)[0] = *v5; // vB = [ [0 0 0] [4 5 6 7] ]
// AND v1 = [0 0 0] because of pointer link between vB[0] and v1.
// Equivalent to:
vB->setVector(0,*v5);
(*v5)(1) = 12;
vB->setVectorPtr(0,v5); // vB = [ [0 0 0] [0 12 0] ]
// Pointer equality between v5 and vB[0].
// The pointer link between vB[0] and v1 has been canceled.
// Warning: when using setVectorPtr(i,w),
// the vector w must be of the same size as the block[i] of v.
About efficiency
""""""""""""""""
As you can see above, for most functionality, two solutions are available: either an overloaded operator or a function without any return value.
For example in the case of matrix addition::
C = A + B;
// or
add(A,B,C);
In a general way, if you need efficiency, always prefer functions to overloaded operators.
The first solution is just there to give a more pleasant and readable, way of writing operations.
Try also to use pointers to objects to avoid temporary and time-consuming copies.
|