Commit 831bfd7c authored by Alexander Danilov's avatar Alexander Danilov
Browse files

Merge branch 'master' of inmost-github

parents f3e4e583 5452e1ea
...@@ -31,7 +31,7 @@ set(HEADER inmost.h ...@@ -31,7 +31,7 @@ set(HEADER inmost.h
container.hpp container.hpp
io.hpp io.hpp
solver_ilu2.hpp solver_ilu2.hpp
# solver_ddpqiluc2.hpp solver_ddpqiluc2.hpp
solver_bcgsl.hpp solver_bcgsl.hpp
solver_prototypes.hpp) solver_prototypes.hpp)
...@@ -56,7 +56,7 @@ option(USE_PARTITIONER_PARMETIS "Use ParMetis partitioner" OFF) ...@@ -56,7 +56,7 @@ option(USE_PARTITIONER_PARMETIS "Use ParMetis partitioner" OFF)
option(USE_PARTITIONER_ZOLTAN "Use Zoltan partitioner" OFF) option(USE_PARTITIONER_ZOLTAN "Use Zoltan partitioner" OFF)
option(USE_SOLVER_PETSC "Use PETSc solver" OFF) option(USE_SOLVER_PETSC "Use PETSc solver" OFF)
option(USE_AUTODIFF_OPENCL "Use OpenCL for automatic differentiation (under work)" OFF) option(USE_AUTODIFF_OPENCL "Use OpenCL for automatic differentiation (under work)" OFF)
option(USE_AUTODIFF_ASMJIT "Use AsmJit for automatic differentiation" ON) option(USE_AUTODIFF_ASMJIT "Use AsmJit for automatic differentiation" OFF)
option(USE_AUTODIFF_EXPRESSION_TEMPLATES "Use c++ expression templates for automatic differentiation" OFF) option(USE_AUTODIFF_EXPRESSION_TEMPLATES "Use c++ expression templates for automatic differentiation" OFF)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_find/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_find/")
......
...@@ -13,14 +13,216 @@ ...@@ -13,14 +13,216 @@
namespace INMOST namespace INMOST
{ {
#if defined(NEW_VERSION)
//! returns offset from the end of precomputed z
void Automatizator::DerivativeFill(expr & var, INMOST_DATA_ENUM_TYPE element, INMOST_DATA_ENUM_TYPE parent, Solver::Row & entries, INMOST_DATA_REAL_TYPE multval, void * user_data)
{
INMOST_DATA_ENUM_TYPE voffset = var.values_offset(element), doffset = var.derivatives_offset(element);
INMOST_DATA_ENUM_TYPE k = var.data.size()-1;
Storage * e = var.current_stencil[element].first;
INMOST_DATA_REAL_TYPE lval, rval, ret;
var.values[doffset+k] = multval;
expr::expr_data * arr = &var.data[0], *it;
//for (expr::data_type::reverse_iterator it = var.data.rbegin(); it != var.data.rend(); ++it)
do
{
it = arr+k;
switch (it->op)
{
case AD_EXT:
assert(parent != ENUMUNDEF);
it->left.e->values[it->left.e->derivatives_offset(parent)+it->right.i] += var.values[doffset+k];
break;
case AD_COND:
{
expr & next = var.values[voffset+it->left.i] > 0.0 ? *it->right.q->left.e : *it->right.q->right.e;
DerivativeFill(next, 0, element, entries,var.values[doffset+k], user_data);
}
break;
case AD_PLUS:
var.values[doffset+it->left.i] += var.values[doffset+k];
var.values[doffset+it->right.i] += var.values[doffset+k];
break;
case AD_MINUS:
var.values[doffset+it->left.i] += var.values[doffset+k];
var.values[doffset+it->right.i] -= var.values[doffset+k];
break;
case AD_MULT:
rval = var.values[voffset+it->right.i];
lval = var.values[voffset+it->left.i];
var.values[doffset+it->left.i] += var.values[doffset+k]*rval;
var.values[doffset+it->right.i] += var.values[doffset+k]*lval;
break;
case AD_DIV:
rval = var.values[voffset+it->right.i];
lval = var.values[voffset+it->left.i];
var.values[doffset+it->left.i] += var.values[doffset+k]/rval;
var.values[doffset+it->right.i] -= var.values[doffset+k]*lval/(rval*rval);
break;
case AD_POW:
ret = var.values[voffset+k];
rval = var.values[voffset+it->right.i];
lval = var.values[voffset+it->left.i];
var.values[doffset+it->right.i] += var.values[doffset+k] * ::log(lval);
var.values[doffset+it->left.i] += var.values[doffset+k] * ret * rval / lval;
break;
case AD_SQRT:
ret = var.values[voffset+k];
var.values[doffset+it->left.i] += 0.5 * var.values[doffset+k] / ret;
break;
case AD_ABS:
lval = var.values[voffset+it->left.i];
var.values[doffset+it->left.i] += var.values[doffset+k] * (lval > 0.0 ? 1.0 : -1.0);
break;
case AD_EXP:
ret = var.values[voffset+k];
var.values[doffset+it->left.i] += var.values[doffset+k] * ret;
break;
case AD_LOG:
lval = var.values[voffset+it->left.i];
var.values[doffset+it->left.i] += var.values[doffset+k] / lval;
break;
case AD_SIN:
lval = var.values[voffset+it->left.i];
var.values[doffset+it->left.i] += var.values[doffset+k] * ::cos(lval);
break;
case AD_COS:
lval = var.values[voffset+it->left.i];
var.values[doffset+it->left.i] -= var.values[doffset+k] * ::sin(lval);
break;
case AD_COND_MARK: break;
case AD_COND_TYPE: break;
case AD_CONST: break;
case AD_MES: break;
case AD_VAL:
{
expr & next = *it->right.e;
next.current_stencil.resize(1);
next.current_stencil[0] = stencil_pair(e,1.0);
next.resize_for_stencil();
var.values[doffset+it->left.i] += var.values[doffset+k] * EvaluateSub(next,0,element,user_data);
break;
}
default:
if (it->op >= AD_FUNC) {}
else if (it->op >= AD_TABLE)
{
lval = var.values[voffset+it->left.i];
var.values[doffset+it->left.i] += var.values[doffset+k] * reg_tables[it->op]->get_derivative(lval);
}
else if (it->op >= AD_STNCL)
{
for (INMOST_DATA_ENUM_TYPE j = 0; j < it->left.e->current_stencil.size(); ++j) if( it->left.e->current_stencil[j].first != NULL )
{
DerivativeFill(*it->left.e, j, ENUMUNDEF, entries, var.values[doffset+k] * it->left.e->current_stencil[j].second, user_data);
}
}
else if (it->op >= AD_CTAG) {}
else if (it->op >= AD_TAG)
{
if (isDynamicValid(e, it->op))
{
entries[GetDynamicIndex(e,it->op,it->left.i)] += var.values[doffset+k];
}
}
else assert(false);
}
} while(k-- != 0);
}
INMOST_DATA_REAL_TYPE Automatizator::EvaluateSub(expr & var, INMOST_DATA_ENUM_TYPE element, INMOST_DATA_ENUM_TYPE parent, void * user_data)
{
INMOST_DATA_ENUM_TYPE k = 0, offset = var.values_offset(element);
Storage * e = var.current_stencil[element].first;
expr::expr_data * arr = &var.data[0], *it;
//for (expr::data_type::iterator it = var.data.begin(); it != var.data.end(); ++it)
do
{
it = arr+k;
switch (it->op)
{
case AD_EXT:
assert(parent != ENUMUNDEF);
var.values[offset+k] = it->left.e->values[it->left.e->values_offset(parent)+it->right.i];
break;
case AD_COND:
{
expr & next = var.values[offset+it->left.i] > 0.0 ? *it->right.q->left.e : *it->right.q->right.e;
next.current_stencil.resize(1);
next.current_stencil[0] = stencil_pair(e,1.0);
next.resize_for_stencil();
var.values[offset+k] = EvaluateSub(next, 0,element, user_data);
}
break;
case AD_PLUS: var.values[offset+k] = var.values[offset+it->left.i] + var.values[offset+it->right.i]; break;
case AD_MINUS: var.values[offset+k] = var.values[offset+it->left.i] - var.values[offset+it->right.i]; break;
case AD_MULT: var.values[offset+k] = var.values[offset+it->left.i] * var.values[offset+it->right.i]; break;
case AD_DIV: var.values[offset+k] = var.values[offset+it->left.i] / var.values[offset+it->right.i]; break;
case AD_POW: var.values[offset+k] = ::pow(var.values[offset+it->left.i], var.values[offset+it->right.i]); break;
case AD_SQRT: var.values[offset+k] = ::sqrt(var.values[offset+it->left.i]); break;
case AD_ABS: var.values[offset+k] = ::fabs(var.values[offset+it->left.i]); break;
case AD_EXP: var.values[offset+k] = ::exp(var.values[offset+it->left.i]); break;
case AD_LOG: var.values[offset+k] = ::log(var.values[offset+it->left.i]); break;
case AD_SIN: var.values[offset+k] = ::sin(var.values[offset+it->left.i]); break;
case AD_COS: var.values[offset+k] = ::cos(var.values[offset+it->left.i]); break;
case AD_CONST: var.values[offset+k] = it->left.r; break;
case AD_COND_TYPE: var.values[offset+k] = ((e->GetElementType() & it->left.i)? 1.0 : -1.0); break;
case AD_COND_MARK: var.values[offset+k] = e->GetMarker(it->left.i) ? 1.0 : -1.0; break;
case AD_MES: assert(!(e->GetElementType() & (ESET | MESH))); m->GetGeometricData(static_cast<Element *>(e), MEASURE, &var.values[offset+k]); break;
case AD_VAL: var.values[offset+k] = var.values[offset+it->left.i]; break;
default:
if (it->op >= AD_FUNC) var.values[offset+k] = reg_funcs[it->op].func(e, user_data);
else if (it->op >= AD_TABLE) var.values[offset+k] = reg_tables[it->op]->get_value(var.values[offset+it->left.i]);
else if (it->op >= AD_STNCL)
{
it->left.e->current_stencil.clear();
GetStencil(it->op,e,user_data,it->left.e->current_stencil);
it->left.e->resize_for_stencil();
var.values[offset+k] = 0.0;
for (INMOST_DATA_ENUM_TYPE j = 0; j < it->left.e->current_stencil.size(); ++j) if( it->left.e->current_stencil[j].first != NULL )
var.values[offset+k] += EvaluateSub(*it->left.e,j,ENUMUNDEF,user_data) * it->left.e->current_stencil[j].second;
}
else if (it->op >= AD_CTAG) var.values[offset+k] = GetStaticValue(e, it->op, it->left.i);
else if (it->op >= AD_TAG) var.values[offset+k] = GetDynamicValue(e, it->op, it->left.i);
else assert(false);
}
//k++;
} while(++k != var.data.size());
return var.values[offset+var.data.size()-1];
}
INMOST_DATA_REAL_TYPE Automatizator::Evaluate(expr & var, Storage * e, void * user_data)
{
var.current_stencil.resize(1);
var.current_stencil[0] = stencil_pair(e,1.0);
var.resize_for_stencil();
return EvaluateSub(var,0,ENUMUNDEF,user_data);
}
INMOST_DATA_REAL_TYPE Automatizator::Derivative(expr & var, Storage * e, Solver::Row & out, Storage::real multiply, void * user_data)
{
INMOST_DATA_REAL_TYPE ret;
var.current_stencil.resize(1);
var.current_stencil[0] = stencil_pair(e,1.0);
var.resize_for_stencil();
ret = EvaluateSub(var,0,ENUMUNDEF,user_data);
DerivativeFill(var, 0, ENUMUNDEF, out, multiply, user_data);
return ret*multiply;
}
#else
INMOST_DATA_REAL_TYPE Automatizator::DerivativePrecompute(const expr & var, Storage * e, precomp_values_t & values, void * user_data) INMOST_DATA_REAL_TYPE Automatizator::DerivativePrecompute(const expr & var, Storage * e, precomp_values_t & values, void * user_data)
{ {
/*
assert(var.op != AD_NONE); assert(var.op != AD_NONE);
INMOST_DATA_REAL_TYPE lval, rval, ret = 0.0; INMOST_DATA_REAL_TYPE lval, rval, ret = 0.0;
switch (var.op) switch (var.op)
{ {
case AD_COND_TYPE:
lval = (e->GetElementType() & reinterpret_cast<ElementType>(var.left))? 1.0 : -1.0;
return lval;
case AD_COND_MARK:
lval = e->GetMarker(reinterpret_cast<MIDType>(var.left))? 1.0 : -1.0;
return lval;
case AD_COND: case AD_COND:
lval = Evaluate(*var.left, e, user_data); lval = Evaluate(*var.left, e, user_data);
rval = DerivativePrecompute(*(lval > 0.0 ? var.right->left : var.right->right), e, values, user_data); rval = DerivativePrecompute(*(lval > 0.0 ? var.right->left : var.right->right), e, values, user_data);
...@@ -54,6 +256,11 @@ namespace INMOST ...@@ -54,6 +256,11 @@ namespace INMOST
ret = ::pow(lval, rval); ret = ::pow(lval, rval);
values.push_back(ret); values.push_back(ret);
return ret*var.coef; return ret*var.coef;
case AD_SQRT:
lval = DerivativePrecompute(*var.left, e, values, user_data);
ret = ::sqrt(lval);
values.push_back(ret);
return ret*var.coef;
case AD_INV: case AD_INV:
lval = DerivativePrecompute(*var.left, e, values, user_data); lval = DerivativePrecompute(*var.left, e, values, user_data);
values.push_back(lval); values.push_back(lval);
...@@ -85,6 +292,11 @@ namespace INMOST ...@@ -85,6 +292,11 @@ namespace INMOST
assert(!(e->GetElementType() & (ESET | MESH))); assert(!(e->GetElementType() & (ESET | MESH)));
m->GetGeometricData(static_cast<Element *>(e), MEASURE, &ret); m->GetGeometricData(static_cast<Element *>(e), MEASURE, &ret);
return ret*var.coef; return ret*var.coef;
case AD_VAL:
lval = DerivativePrecompute(*var.left, e, values, user_data);
rval = Evaluate(*var.left,e,user_data);
values.push_back(rval);
return lval*var.coef;
} }
if (var.op >= AD_FUNC) if (var.op >= AD_FUNC)
{ {
...@@ -100,14 +312,14 @@ namespace INMOST ...@@ -100,14 +312,14 @@ namespace INMOST
} }
else if (var.op >= AD_STNCL) else if (var.op >= AD_STNCL)
{ {
stencil_kind_domain st = reg_stencils[var.op]; stencil_kind_domain & st = reg_stencils[var.op];
assert(st.domainmask == 0 || e->GetMarker(st.domainmask)); assert(st.domainmask == 0 || e->GetMarker(st.domainmask));
if (st.kind == 0) if (st.kind == 0)
{ {
Storage::reference_array elems = e->ReferenceArray(static_cast<stencil_tag *>(st.link)->elements); Storage::reference_array elems = e->ReferenceArray(static_cast<stencil_tag *>(st.link)->elements);
Storage::real_array coefs = e->RealArray(static_cast<stencil_tag *>(st.link)->coefs); Storage::real_array coefs = e->RealArray(static_cast<stencil_tag *>(st.link)->coefs);
assert(elems.size() == coefs.size()); assert(elems.size() == coefs.size());
for (INMOST_DATA_ENUM_TYPE k = 0; k < elems.size(); ++k) for (INMOST_DATA_ENUM_TYPE k = 0; k < elems.size(); ++k) if( elems[k] != NULL )
{ {
lval = DerivativePrecompute(*var.left, elems[k], values, user_data); lval = DerivativePrecompute(*var.left, elems[k], values, user_data);
ret += lval * coefs[k]; ret += lval * coefs[k];
...@@ -117,7 +329,7 @@ namespace INMOST ...@@ -117,7 +329,7 @@ namespace INMOST
{ {
stencil_pairs get_st; stencil_pairs get_st;
reinterpret_cast<stencil_callback>(st.link)(e, get_st, user_data); reinterpret_cast<stencil_callback>(st.link)(e, get_st, user_data);
for (INMOST_DATA_ENUM_TYPE k = 0; k < get_st.size(); ++k) for (INMOST_DATA_ENUM_TYPE k = 0; k < get_st.size(); ++k) if( get_st[k].first != NULL )
{ {
lval = DerivativePrecompute(*var.left, get_st[k].first, values, user_data); lval = DerivativePrecompute(*var.left, get_st[k].first, values, user_data);
ret += lval * get_st[k].second; ret += lval * get_st[k].second;
...@@ -138,17 +350,18 @@ namespace INMOST ...@@ -138,17 +350,18 @@ namespace INMOST
return ret*var.coef; return ret*var.coef;
} }
assert(false); assert(false);
*/
return 0.0; return 0.0;
} }
//! returns offset from the end of precomputed values //! returns offset from the end of precomputed values
void Automatizator::DerivativeFill(const expr & var, Storage * e, Solver::Row & entries, precomp_values_t & values, INMOST_DATA_REAL_TYPE multval, void * user_data) void Automatizator::DerivativeFill(const expr & var, Storage * e, Solver::Row & entries, precomp_values_t & values, INMOST_DATA_REAL_TYPE multval, void * user_data)
{ {
/*
assert(var.op != AD_NONE); assert(var.op != AD_NONE);
INMOST_DATA_REAL_TYPE lval, rval, ret; INMOST_DATA_REAL_TYPE lval, rval, ret;
switch (var.op) switch (var.op)
{ {
case AD_COND_MARK:
case AD_COND_TYPE:
return;
case AD_COND: case AD_COND:
lval = values.back(); values.pop_back(); lval = values.back(); values.pop_back();
DerivativeFill(*(lval > 0.0 ? var.right->left : var.right->right), e, entries, values, multval*var.coef, user_data); DerivativeFill(*(lval > 0.0 ? var.right->left : var.right->right), e, entries, values, multval*var.coef, user_data);
...@@ -180,6 +393,10 @@ namespace INMOST ...@@ -180,6 +393,10 @@ namespace INMOST
DerivativeFill(*var.right, e, entries, values, multval * ret * ::log(lval) * var.coef, user_data); DerivativeFill(*var.right, e, entries, values, multval * ret * ::log(lval) * var.coef, user_data);
DerivativeFill(*var.left, e, entries, values, multval * ret * rval / lval * var.coef, user_data); DerivativeFill(*var.left, e, entries, values, multval * ret * rval / lval * var.coef, user_data);
return; return;
case AD_SQRT:
ret = values.back(); values.pop_back();
DerivativeFill(*var.left, e, entries, values, 0.5 * multval / ret * var.coef, user_data);
return;
case AD_INV: case AD_INV:
lval = values.back(); values.pop_back(); lval = values.back(); values.pop_back();
DerivativeFill(*var.left, e, entries, values, -multval / (lval * lval) * var.coef, user_data); DerivativeFill(*var.left, e, entries, values, -multval / (lval * lval) * var.coef, user_data);
...@@ -206,6 +423,10 @@ namespace INMOST ...@@ -206,6 +423,10 @@ namespace INMOST
return; return;
case AD_CONST: return; case AD_CONST: return;
case AD_MES: return; case AD_MES: return;
case AD_VAL:
rval = values.back(); values.pop_back();
DerivativeFill(*var.left, e, entries, values, multval * var.coef * rval, user_data);
return;
} }
if (var.op >= AD_FUNC) if (var.op >= AD_FUNC)
{ {
...@@ -219,21 +440,21 @@ namespace INMOST ...@@ -219,21 +440,21 @@ namespace INMOST
} }
else if (var.op >= AD_STNCL) else if (var.op >= AD_STNCL)
{ {
stencil_kind_domain st = reg_stencils[var.op]; stencil_kind_domain & st = reg_stencils[var.op];
assert(st.domainmask == 0 || e->GetMarker(st.domainmask)); assert(st.domainmask == 0 || e->GetMarker(st.domainmask));
if (st.kind == 0) if (st.kind == 0)
{ {
Storage::reference_array elems = e->ReferenceArray(static_cast<stencil_tag *>(st.link)->elements); Storage::reference_array elems = e->ReferenceArray(static_cast<stencil_tag *>(st.link)->elements);
Storage::real_array coefs = e->RealArray(static_cast<stencil_tag *>(st.link)->coefs); Storage::real_array coefs = e->RealArray(static_cast<stencil_tag *>(st.link)->coefs);
assert(elems.size() == coefs.size()); assert(elems.size() == coefs.size());
for (INMOST_DATA_ENUM_TYPE k = elems.size(); k > 0; --k) for (INMOST_DATA_ENUM_TYPE k = elems.size(); k > 0; --k) if( elems[k-1] != NULL )
DerivativeFill(*var.left, elems[k - 1], entries, values, var.coef * coefs[k - 1] * multval, user_data); DerivativeFill(*var.left, elems[k - 1], entries, values, var.coef * coefs[k - 1] * multval, user_data);
} }
else if (st.kind == 1) else if (st.kind == 1)
{ {
stencil_pairs get_st; stencil_pairs get_st;
reinterpret_cast<stencil_callback>(st.link)(e, get_st, user_data); reinterpret_cast<stencil_callback>(st.link)(e, get_st, user_data);
for (INMOST_DATA_ENUM_TYPE k = get_st.size(); k > 0; --k) for (INMOST_DATA_ENUM_TYPE k = get_st.size(); k > 0; --k) if( get_st[k-1].first != NULL )
DerivativeFill(*var.left, get_st[k - 1].first, entries, values, var.coef * get_st[k - 1].second*multval, user_data); DerivativeFill(*var.left, get_st[k - 1].first, entries, values, var.coef * get_st[k - 1].second*multval, user_data);
} }
return; return;
...@@ -244,74 +465,76 @@ namespace INMOST ...@@ -244,74 +465,76 @@ namespace INMOST
if (isDynamicValid(e, var.op)) if (isDynamicValid(e, var.op))
{ {
INMOST_DATA_ENUM_TYPE ind = GetDynamicIndex(e, var.op, *(INMOST_DATA_ENUM_TYPE *)(&var.left)); INMOST_DATA_ENUM_TYPE ind = GetDynamicIndex(e, var.op, *(INMOST_DATA_ENUM_TYPE *)(&var.left));
std::cout << ind << ", " << multval*var.coef << std::endl;
entries[ind] += multval * var.coef; entries[ind] += multval * var.coef;
} }
return; return;
} }
assert(false); assert(false);
*/
return; return;
} }
INMOST_DATA_REAL_TYPE Automatizator::Evaluate(const expr & var, Storage * e, void * user_data) INMOST_DATA_REAL_TYPE Automatizator::Evaluate(const expr & var, Storage * e, void * user_data)
{ {
return EvaluateSub(var, e, user_data, NULL); assert(var.op != AD_NONE);
} switch (var.op)
INMOST_DATA_REAL_TYPE Automatizator::EvaluateSub(const expr & var, Storage * e, void * user_data, values_container * parent_values)
{ {
values_container values(var.data.size()); case AD_COND_MARK: return e->GetMarker(reinterpret_cast<MIDType>(var.left)) ? 1.0 : -1.0;
INMOST_DATA_ENUM_TYPE k = 0; case AD_COND_TYPE: return (e->GetElementType() & reinterpret_cast<ElementType>(var.left)) ? 1.0 : -1.0;
for (expr::data_type::const_iterator it = var.data.begin(); it != var.data.end(); ++it) case AD_COND: return Evaluate(*(Evaluate(*var.left, e, user_data) > 0.0 ? var.right->left : var.right->right), e, user_data)*var.coef;
case AD_PLUS: return (Evaluate(*var.left, e, user_data) + Evaluate(*var.right, e, user_data))*var.coef;
case AD_MINUS: return (Evaluate(*var.left, e, user_data) - Evaluate(*var.right, e, user_data))*var.coef;
case AD_MULT: return (Evaluate(*var.left, e, user_data) * Evaluate(*var.right, e, user_data))*var.coef;
case AD_DIV: return (Evaluate(*var.left, e, user_data) / Evaluate(*var.right, e, user_data))*var.coef;
case AD_INV: return var.coef / Evaluate(*var.left, e, user_data);
case AD_POW: return ::pow(Evaluate(*var.left, e, user_data), Evaluate(*var.right, e, user_data))*var.coef;
case AD_SQRT: return ::sqrt(Evaluate(*var.left, e, user_data))*var.coef;
case AD_ABS: return ::fabs(Evaluate(*var.left, e, user_data))*var.coef;
case AD_EXP: return ::exp(Evaluate(*var.left, e, user_data))*var.coef;
case AD_LOG: return ::log(Evaluate(*var.left, e, user_data))*var.coef;
case AD_SIN: return ::sin(Evaluate(*var.left, e, user_data))*var.coef;
case AD_COS: return ::cos(Evaluate(*var.left, e, user_data))*var.coef;
case AD_CONST: return var.coef;
case AD_MES: assert(!(e->GetElementType() & (ESET | MESH))); Storage::real ret; m->GetGeometricData(static_cast<Element *>(e), MEASURE, &ret); return ret*var.coef;
case AD_VAL: return Evaluate(*var.left,e,user_data)*var.coef;
}
if (var.op >= AD_FUNC) return reg_funcs[var.op].func(e, user_data);
if (var.op >= AD_TABLE) return reg_tables[var.op]->get_value(Evaluate(*var.left, e, user_data))*var.coef;
if (var.op >= AD_STNCL)
{ {
switch (it->op) INMOST_DATA_REAL_TYPE ret = 0.0;
stencil_kind_domain & st = reg_stencils[var.op];
assert(st.domainmask == 0 || e->GetMarker(st.domainmask));
if (st.kind == 0)
{ {
case AD_EXT: values[k] = (*parent_values)[it->right.i]; break; Storage::reference_array elems = e->ReferenceArray(static_cast<stencil_tag *>(st.link)->elements);
case AD_COND: Storage::real_array coefs = e->RealArray(static_cast<stencil_tag *>(st.link)->coefs);
if (values[it->left.i] > 0.0) assert(elems.size() == coefs.size());
values[k] = EvaluateSub(*it->right.q->left.e, e, user_data,&values); for (INMOST_DATA_ENUM_TYPE k = 0; k < elems.size(); ++k) if( elems[k] != NULL )
else ret += var.coef * Evaluate(*var.left, elems[k], user_data) * coefs[k];
values[k] = EvaluateSub(*it->right.q->right.e, e, user_data,&values); }
break; else if (st.kind == 1)
case AD_PLUS: values[k] = values[it->left.i] + values[it->right.i]; break;
case AD_MINUS: values[k] = values[it->left.i] - values[it->right.i]; break;
case AD_MULT: values[k] = values[it->left.i] * values[it->right.i]; break;
case AD_DIV: values[k] = values[it->left.i] / values[it->right.i]; break;
case AD_POW: values[k] = ::pow(values[it->left.i], values[it->right.i]); break;
case AD_ABS: values[k] = ::fabs(values[it->left.i]); break;
case AD_EXP: values[k] = ::exp(values[it->left.i]); break;
case AD_LOG: values[k] = ::log(values[it->left.i]); break;
case AD_SIN: values[k] = ::sin(values[it->left.i]); break;
case AD_COS: values[k] = ::cos(values[it->left.i]); break;
case AD_CONST: values[k] = it->left.r; break;
case AD_MES: assert(!(e->GetElementType() & (ESET | MESH))); m->GetGeometricData(static_cast<Element *>(e), MEASURE, &values[k]); break;
default:
if (it->op >= AD_FUNC) values[k] = reg_funcs[it->op].func(e, user_data);
else if (it->op >= AD_TABLE) values[k] = reg_tables[it->op]->get_value(values[it->left.i]);
else if (it->op >= AD_STNCL)
{ {
stencil_pairs get_st; stencil_pairs get_st;
GetStencil(it->op, e, user_data, get_st); reinterpret_cast<stencil_callback>(st.link)(e, get_st, user_data);
values[k] = 0.0; for (INMOST_DATA_ENUM_TYPE k = 0; k < get_st.size(); ++k) if ( get_st[k].first != NULL )
for (INMOST_DATA_ENUM_TYPE k = 0; k < get_st.size(); ++k) ret += var.coef * Evaluate(*var.left, get_st[k].first, user_data) * get_st[k].second;
values[k] += EvaluateSub(*it->left.e, get_st[k].first, user_data,NULL) * get_st[k].second;
}
else if (it->op >= AD_CTAG) values[k] = GetStaticValue(e, it->op, it->left.i);
else if (it->op >= AD_TAG) values[k] = GetDynamicValue(e, it->op, it->left.i);
else assert(false);
} }
k++; return ret;
} }
return values[var.data.size()-1]; if (var.op >= AD_CTAG) return GetStaticValue(e, var.op, *(INMOST_DATA_ENUM_TYPE *)(&var.left))*var.coef;
if (var.op >= AD_TAG) return GetDynamicValue(e, var.op, *(INMOST_DATA_ENUM_TYPE *)(&var.left))*var.coef;
assert(false);
return 0.0;
} }
INMOST_DATA_REAL_TYPE Automatizator::Derivative(const expr & var, Storage * e, Solver::Row & out, void * user_data) INMOST_DATA_REAL_TYPE Automatizator::Derivative(const expr & var, Storage * e, Solver::Row & out, Storage::real multiply, void * user_data)
{ {
INMOST_DATA_REAL_TYPE ret; INMOST_DATA_REAL_TYPE ret;
precomp_values_t values; precomp_values_t values;
ret = DerivativePrecompute(var, e, values, user_data); ret = DerivativePrecompute(var, e, values, user_data);
DerivativeFill(var, e, out, values, 1.0, user_data); DerivativeFill(var, e, out, values, multiply, user_data);
return ret; return ret*multiply;
} }
#endif
Automatizator::Automatizator(Mesh * m) :first_num(0), last_num(0), m(m) {} Automatizator