00001 #pragma once
00002 #ifndef OPENGM_OPERATIONWRAPPER_HXX
00003 #define OPENGM_OPERATIONWRAPPER_HXX
00004
00005 #include "opengm/utilities/functors.hxx"
00006 #include "opengm/functions/operations/operator.hxx"
00007 #include "opengm/utilities/metaprogramming.hxx"
00008
00009 namespace opengm {
00010
00012
00013 namespace functionwrapper {
00014 struct FactorFlag;
00015 struct IndependentFactorFlag;
00016 struct IndependentFactorOrFactorFlag;
00017 struct ScalarFlag;
00018 struct ErrorFlag;
00019
00020 namespace executor {
00021
00022 namespace unary {
00023
00024 template<class A, class B, class OP, size_t IX, size_t DX, bool END>
00025 class OperationExecutor;
00026
00027 template<class A, class B, class OP, size_t IX, size_t DX>
00028 class OperationExecutor<A, B, OP, IX, DX, false>
00029 {
00030 public:
00031 typedef std::vector<typename A::IndexType> ViType;
00032
00033 static void op
00034 (
00035 const A& a,
00036 B& b,
00037 OP op,
00038 const size_t rtia
00039 ) {
00040 if(rtia==IX) {
00041 typedef typename meta::GetFunction<A, IX>::FunctionType FunctionTypeA;
00042 typedef typename meta::GetFunction<B, 0>::FunctionType FunctionTypeB;
00043 const FunctionTypeA& fa=meta::GetFunction<A, IX>::get(a);
00044 FunctionTypeB& fb=meta::GetFunction<B, 0>::get(b);
00045 b.variableIndexSequence()=a.variableIndexSequence();
00046 typedef opengm::UnaryOperationImpl<FunctionTypeA, FunctionTypeB, OP> UnaryOperationType;
00047 UnaryOperationType::op(fa, fb, op);
00048 }
00049 else {
00050 typedef OperationExecutor
00051 <
00052 A, B, OP,
00053 IX+1,
00054 DX,
00055 meta::Bool<IX+1==DX>::value
00056 > NewExecutorType;
00057 NewExecutorType::op(a, b, op, rtia);
00058 }
00059 }
00060 };
00061
00062 template<class A, class B, class OP, size_t IX, size_t DX>
00063 class OperationExecutor<A, B, OP, IX, DX, true>
00064 {
00065 public:
00066 static void op
00067 (
00068 const A& a,
00069 B& b,
00070 OP op,
00071 const size_t rtia
00072 ) {
00073 throw RuntimeError("Incorrect function type id.");
00074 }
00075 };
00076
00077 }
00078
00079 namespace binary {
00080
00081 template<class A, class B, class C, class OP, size_t IX, size_t IY, size_t DX, size_t DY, bool END>
00082 class OperationExecutor;
00083
00084 template<class A, class B, class C, class OP, size_t IX, size_t IY, size_t DX, size_t DY>
00085 class OperationExecutor<A, B, C, OP, IX, IY, DX, DY, false>
00086 {
00087 public:
00088 typedef std::vector<typename A::IndexType> ViType;
00089 static void op
00090 (
00091 const A& a,
00092 const B& b,
00093 C& c,
00094 OP op,
00095 const ViType& via,
00096 const ViType& vib,
00097 ViType& vic,
00098 const size_t rtia,
00099 const size_t rtib
00100 ) {
00101 if(rtia==IX && rtib==IY) {
00102 typedef typename meta::GetFunction<A, IX>::FunctionType FunctionTypeA;
00103 typedef typename meta::GetFunction<B, IY>::FunctionType FunctionTypeB;
00104 typedef typename meta::GetFunction<C, 0>::FunctionType FunctionTypeC;
00105 const FunctionTypeA& fa = meta::GetFunction<A, IX>::get(a);
00106 const FunctionTypeB& fb = meta::GetFunction<B, IY>::get(b);
00107 FunctionTypeC& fc = meta::GetFunction<C, 0>::get(c);
00108 typedef opengm::BinaryOperationImpl<FunctionTypeA, FunctionTypeB, FunctionTypeC, OP> BinaryOperationType;
00109 BinaryOperationType::op(fa, fb, fc, via, vib, vic, op);
00110 }
00111 else {
00112 typedef typename meta::If
00113 <
00114 IX==DX-1,
00115 meta::SizeT<0>,
00116 meta::SizeT<IX+1>
00117 >::type IXNewType;
00118 typedef typename meta::If
00119 <
00120 IX==DX-1,
00121 meta::SizeT<IY+1>,
00122 meta::SizeT<IY>
00123 >::type IYNewType;
00124 typedef OperationExecutor
00125 <
00126 A, B, C, OP,
00127 IXNewType::value,
00128 IYNewType::value,
00129 DX, DY,
00130 meta::Bool< meta::And<(IX==DX-1) , (IY==DY-1)>::value >::value
00131 > NewExecutorType;
00132 NewExecutorType::op(a, b, c, op, via, vib, vic, rtia, rtib);
00133 }
00134 }
00135 };
00136
00137 template<class A, class B, class C, class OP, size_t IX, size_t IY, size_t DX, size_t DY>
00138 class OperationExecutor<A, B, C, OP, IX, IY, DX, DY, true>
00139 {
00140 public:
00141 typedef std::vector<typename A::IndexType> ViType;
00142 static void op
00143 (
00144 const A& a,
00145 const B& b,
00146 C& c,
00147 OP op,
00148 const ViType& via,
00149 const ViType& vib,
00150 ViType& vic,
00151 const size_t rtia,
00152 const size_t rtib
00153 ) {
00154 throw RuntimeError("Incorrect function type id.");
00155 }
00156 };
00157
00158 template<class A, class B, class OP, size_t IY, size_t DY, bool END>
00159 class InplaceOperationExecutor;
00160
00161 template<class A, class B, class OP, size_t IY, size_t DY>
00162 class InplaceOperationExecutor<A, B, OP, IY, DY, false>
00163 {
00164 public:
00165 typedef std::vector<typename A::IndexType> ViType;
00166 static void op
00167 (
00168 A& a,
00169 const B& b,
00170 OP op,
00171 const size_t rtib
00172 ) {
00173 if(rtib==IY) {
00174 typedef typename meta::GetFunction<A, 0>::FunctionType FunctionTypeA;
00175 typedef typename meta::GetFunction<B, IY>::FunctionType FunctionTypeB;
00176 typedef typename FunctionTypeA::IndexType IndexType;
00177 FunctionTypeA& fa=meta::GetFunction<A, 0>::get(a);
00178 const FunctionTypeB& fb=meta::GetFunction<B, IY>::get(b);
00179 std::vector<IndexType>& via=a.variableIndexSequence();
00180 const std::vector<IndexType>& vib=b.variableIndexSequence();
00181 typedef opengm::BinaryOperationInplaceImpl<FunctionTypeA, FunctionTypeB, OP> BinaryOperationType;
00182 BinaryOperationType::op(fa, fb, via, vib, op);
00183 }
00184 else {
00185 typedef InplaceOperationExecutor
00186 <
00187 A, B, OP,
00188 IY+1,
00189 DY,
00190 meta::Bool<IY+1==DY>::value
00191 > NewExecutorType;
00192 NewExecutorType::op(a, b, op, rtib);
00193 }
00194 }
00195 };
00196
00197 template<class A, class B, class OP, size_t IY, size_t DY>
00198 class InplaceOperationExecutor<A, B, OP, IY, DY, true>
00199 {
00200 public:
00201 typedef std::vector<typename A::IndexType> ViType;
00202 static void op
00203 (
00204 A& a,
00205 const B& b,
00206 OP op,
00207 const size_t rtib
00208 ) {
00209 throw RuntimeError("Incorrect function type id.");
00210 }
00211 };
00212
00213 }
00214
00215 }
00216
00217 namespace unary {
00218
00219 template<class A, class B, class OP, class FlagA, class FlagB>
00220 class OperationWrapper;
00221
00222
00223 template<class A, class OP, class FlagA>
00224 class InplaceOperationWrapper;
00225
00226
00227
00228 template<class A, class B, class OP>
00229 class OperationWrapper<A, B, OP, IndependentFactorOrFactorFlag, IndependentFactorFlag>
00230 {
00231 public:
00232 static void op
00233 (
00234 const A& a,
00235 B& b,
00236 OP op
00237 ) {
00238 typedef typename meta::EvalIf
00239 <
00240 meta::IsIndependentFactor<A>::value,
00241 meta::Self<meta::SizeT<1> >,
00242 meta::Self< meta::SizeT<A::NrOfFunctionTypes> >
00243 >::type NFA;
00244 typedef executor::unary::OperationExecutor<A, B, OP, 0, NFA::value, NFA::value==0> ExecutorType;
00245 ExecutorType::op(a, b, op, opengm::meta::GetFunctionTypeIndex<A>::get(a));
00246 }
00247 };
00248
00249
00250
00251 template<class A, class B, class OP>
00252 class OperationWrapper<A, B, OP, ScalarFlag, ScalarFlag>
00253 {
00254 public:
00255 static void op
00256 (
00257 const A& a,
00258 B& b,
00259 OP op
00260 ) {
00261 b = op(a);
00262 }
00263 };
00264
00265 template<class A, class B, class OP>
00266 class OperationWrapperSelector
00267 {
00268 typedef meta::Bool <opengm::meta::IsFundamental<A>::value> IsAScalarType;
00269 typedef meta::Bool <opengm::meta::IsFundamental<B>::value> IsBScalarType;
00270 typedef meta::Bool <opengm::meta::IsIndependentFactor<A>::value> IsAIndependentFactorType;
00271 typedef meta::Bool <opengm::meta::IsIndependentFactor<B>::value> IsBIndependentFactorType;
00272 typedef meta::Bool <opengm::meta::IsFactor<A>::value> IsAFactorType;
00273 typedef meta::Bool <opengm::meta::IsFactor<B>::value> IsBFactorType;
00274
00275 typedef typename meta::TypeListGenerator
00276 <
00277 meta::SwitchCase<IsAScalarType::value, ScalarFlag>,
00278 meta::SwitchCase< meta::Or<IsAIndependentFactorType::value , IsAFactorType::value>::value , IndependentFactorOrFactorFlag>
00279 >::type CaseListA;
00280 typedef typename meta::Switch<CaseListA, ErrorFlag>::type FlagA;
00281 typedef typename meta::TypeListGenerator
00282 <
00283 meta::SwitchCase<IsBScalarType::value, ScalarFlag>,
00284 meta::SwitchCase<IsBIndependentFactorType::value, IndependentFactorFlag>
00285 >::type CaseListB;
00286 typedef typename meta::Switch<CaseListB, ErrorFlag>::type FlagB;
00287
00288 public:
00289 static void op
00290 (
00291 const A& a,
00292 B& b,
00293 OP op
00294 ) {
00295 unary::OperationWrapper<A, B, OP, FlagA, FlagB>::op(a, b, op);
00296 }
00297 };
00298
00299
00300 template<class A, class OP>
00301 class InplaceOperationWrapper<A, OP, IndependentFactorFlag>
00302 {
00303 public:
00304 static void op
00305 (
00306 A& a,
00307 OP op
00308 ) {
00309 typedef typename meta::GetFunction<A, 0>::FunctionType FunctionTypeA;
00310 FunctionTypeA& fa = meta::GetFunction<A, 0>::get(a);
00311 typedef typename opengm::UnaryOperationInplaceImpl<FunctionTypeA, OP> UnaryOperationType;
00312 UnaryOperationType::op(fa, op);
00313 }
00314 };
00315
00316
00317 template<class A, class OP>
00318 class InplaceOperationWrapper<A, OP, ScalarFlag>
00319 {
00320 public:
00321 static void op
00322 (
00323 A& a,
00324 OP op
00325 ) {
00326 a = op(a);
00327 }
00328 };
00329
00330 template<class A, class OP>
00331 class InplaceOperationWrapperSelector
00332 {
00333 typedef meta::Bool <opengm::meta::IsFundamental<A>::value> IsAScalarType;
00334 typedef meta::Bool <opengm::meta::IsIndependentFactor<A>::value> IsAIndependentFactorType;
00335
00336 typedef typename meta::TypeListGenerator
00337 <
00338 meta::SwitchCase<IsAScalarType::value, ScalarFlag>,
00339 meta::SwitchCase<IsAIndependentFactorType::value, IndependentFactorFlag>
00340 >::type CaseListA;
00341 typedef typename meta::Switch<CaseListA, ErrorFlag>::type FlagA;
00342 typedef unary::InplaceOperationWrapper<A, OP, FlagA> OperationWrapperType;
00343
00344 public:
00345 static void op
00346 (
00347 A& a,
00348 OP op
00349 ) {
00350 OperationWrapperType::op(a, op);
00351 }
00352 };
00353
00354 }
00355
00356 namespace binary {
00357
00358 template<class A, class B, class C, class OP, class FlagA, class FlagB, class FlagC>
00359 class OperationWrapper;
00360 template<class A, class B, class OP, class FlagA, class FlagB>
00361 class InplaceOperationWrapper;
00362
00363 template<class A, class B, class C, class OP>
00364 class OperationWrapper<A, B, C, OP, IndependentFactorOrFactorFlag, ScalarFlag, IndependentFactorFlag>
00365 {
00366 public:
00367 static void op
00368 (
00369 const A& a,
00370 const B& b,
00371 C& c,
00372 OP op
00373 ) {
00374 typedef typename opengm::BinaryToUnaryFunctor<B, OP, false> BTUFunctor;
00375 BTUFunctor btufunctor(b, op);
00376 opengm::functionwrapper::unary::OperationWrapperSelector<A, C, BTUFunctor>::op(a, c, btufunctor);
00377 }
00378 };
00379
00380 template<class A, class B, class C, class OP>
00381 class OperationWrapper<A, B, C, OP, ScalarFlag, IndependentFactorOrFactorFlag, IndependentFactorFlag>
00382 {
00383 public:
00384 static void op
00385 (
00386 const A& a,
00387 const B& b,
00388 C& c, OP op
00389 ) {
00390 typedef opengm::SwapArgumemtFunctor<A, OP> SwapFunctorType;
00391 OperationWrapper<B, A, C, SwapFunctorType, IndependentFactorOrFactorFlag, ScalarFlag, IndependentFactorFlag >::op(b, a, c, SwapFunctorType(op));
00392 }
00393 };
00394
00395 template<class A, class B, class C, class OP>
00396 class OperationWrapper<A, B, C, OP, ScalarFlag, ScalarFlag, ScalarFlag>
00397 {
00398 public:
00399 static void op
00400 (
00401 const A& a,
00402 const B& b,
00403 C& c,
00404 OP op
00405 ) {
00406 c = op(a, b);
00407 }
00408 };
00409
00410 template<class A, class B, class C, class OP>
00411 class OperationWrapper<A, B, C, OP, IndependentFactorOrFactorFlag, IndependentFactorOrFactorFlag, IndependentFactorFlag>
00412 {
00413 public:
00414 typedef std::vector<typename A::IndexType> ViType;
00415
00416 static void op
00417 (
00418 const A& a,
00419 const B& b,
00420 C& c,
00421 OP op
00422 ) {
00423 const ViType& viA = a.variableIndexSequence();
00424 const ViType& viB = b.variableIndexSequence();
00425 ViType& viC = c.variableIndexSequence();
00426 typedef typename meta::EvalIf
00427 <
00428 meta::IsIndependentFactor<A>::value,
00429 meta::Self<meta::SizeT<1> >,
00430 meta::Self< meta::SizeT<A::NrOfFunctionTypes> >
00431 >::type NFA;
00432 typedef typename meta::EvalIf
00433 <
00434 meta::IsIndependentFactor<B>::value,
00435 meta::Self<meta::SizeT<1> >,
00436 meta::Self< meta::SizeT<B::NrOfFunctionTypes> >
00437 >::type NFB;
00438 typedef executor::binary::OperationExecutor<A, B, C, OP, 0, 0, NFA::value, NFB::value, meta::And<NFA::value==0 , NFB::value==0 >::value > ExecutorType;
00439 ExecutorType::op
00440 (
00441 a, b, c,
00442 op,
00443 viA, viB, viC,
00444 opengm::meta::GetFunctionTypeIndex<A>::get(a),
00445 opengm::meta::GetFunctionTypeIndex<B>::get(b)
00446 );
00447 }
00448 };
00449
00450 template<class A, class B, class C, class OP>
00451 class OperationWrapperSelector
00452 {
00453 typedef meta::Bool <opengm::meta::IsFundamental<A>::value> IsAScalarType;
00454 typedef meta::Bool <opengm::meta::IsFundamental<B>::value> IsBScalarType;
00455 typedef meta::Bool <opengm::meta::IsFundamental<C>::value> IsCScalarType;
00456 typedef meta::Bool <opengm::meta::IsIndependentFactor<A>::value> IsAIndependentFactorType;
00457 typedef meta::Bool <opengm::meta::IsIndependentFactor<B>::value> IsBIndependentFactorType;
00458 typedef meta::Bool <opengm::meta::IsIndependentFactor<C>::value> IsCIndependentFactorType;
00459 typedef meta::Bool <opengm::meta::IsFactor<A>::value> IsAFactorType;
00460 typedef meta::Bool <opengm::meta::IsFactor<B>::value> IsBFactorType;
00461 typedef meta::Bool <opengm::meta::IsFactor<C>::value> IsCFactorType;
00462 typedef typename meta::TypeListGenerator
00463 <
00464 meta::SwitchCase<IsAScalarType::value, ScalarFlag>,
00465 meta::SwitchCase<IsAIndependentFactorType::value ||IsAFactorType::value, IndependentFactorOrFactorFlag>
00466 >::type CaseListA;
00467 typedef typename meta::Switch<CaseListA, ErrorFlag>::type FlagA;
00468 typedef typename meta::TypeListGenerator
00469 <
00470 meta::SwitchCase<IsBScalarType::value, ScalarFlag>,
00471 meta::SwitchCase<IsBIndependentFactorType::value ||IsBFactorType::value, IndependentFactorOrFactorFlag>
00472 >::type CaseListB;
00473 typedef typename meta::Switch<CaseListB, ErrorFlag>::type FlagB;
00474 typedef typename meta::TypeListGenerator
00475 <
00476 meta::SwitchCase<IsCScalarType::value, ScalarFlag>,
00477 meta::SwitchCase<IsCIndependentFactorType::value, IndependentFactorFlag>
00478 >::type CaseListC;
00479 typedef typename meta::Switch<CaseListC, ErrorFlag>::type FlagC;
00480 typedef binary::OperationWrapper<A, B, C, OP, FlagA, FlagB, FlagC> OperationWrapperType;
00481
00482 public:
00483 static void op
00484 (
00485 const A& a,
00486 const B& b,
00487 C& c,
00488 OP op
00489 ) {
00490 OperationWrapperType::op(a, b, c, op);
00491 }
00492 };
00493
00494 template<class A, class B, class OP>
00495 class InplaceOperationWrapper<A, B, OP, ScalarFlag, ScalarFlag>
00496 {
00497 public:
00498 static void op
00499 (
00500 A& a,
00501 const B& b,
00502 OP op
00503 ) {
00504 a = op(a, b);
00505 }
00506 };
00507
00508 template<class A, class B, class OP>
00509 class InplaceOperationWrapper<A, B, OP, IndependentFactorFlag, ScalarFlag>
00510 {
00511 public:
00512 static void op
00513 (
00514 A& a,
00515 const B& b,
00516 OP op
00517 ) {
00518 typedef typename opengm::BinaryToUnaryFunctor<B, OP, false> BTUFunctor;
00519 BTUFunctor btufunctor(b, op);
00520 opengm::UnaryOperationInplaceImpl<A, BTUFunctor>::op(a, btufunctor);
00521 }
00522 };
00523
00524 template<class A, class B, class OP>
00525 class InplaceOperationWrapper<A, B, OP, IndependentFactorFlag, IndependentFactorOrFactorFlag>
00526 {
00527 public:
00528 static void op
00529 (
00530 A& a,
00531 const B& b,
00532 OP op
00533 ) {
00534 typedef typename meta::EvalIf
00535 <
00536 meta::IsIndependentFactor<B>::value,
00537 meta::Self<meta::SizeT<1> >,
00538 meta::Self< meta::SizeT<B::NrOfFunctionTypes> >
00539 >::type NFB;
00540 typedef executor::binary::InplaceOperationExecutor<A, B, OP, 0, NFB::value, meta::Bool<NFB::value==0>::value> ExecutorType;
00541 ExecutorType::op(a, b, op, opengm::meta::GetFunctionTypeIndex<B>::get(b));
00542 }
00543 };
00544
00545 template<class A, class B, class OP>
00546 class InplaceOperationWrapperSelector
00547 {
00548 typedef meta::Bool <opengm::meta::IsFundamental<A>::value> IsAScalarType;
00549 typedef meta::Bool <opengm::meta::IsFundamental<B>::value> IsBScalarType;
00550 typedef meta::Bool <opengm::meta::IsIndependentFactor<A>::value> IsAIndependentFactorType;
00551 typedef meta::Bool <opengm::meta::IsIndependentFactor<B>::value> IsBIndependentFactorType;
00552 typedef meta::Bool <opengm::meta::IsFactor<A>::value> IsAFactorType;
00553 typedef meta::Bool <opengm::meta::IsFactor<B>::value> IsBFactorType;
00554 typedef typename meta::TypeListGenerator
00555 <
00556 meta::SwitchCase<IsAScalarType::value, ScalarFlag>,
00557 meta::SwitchCase<IsAIndependentFactorType::value , IndependentFactorFlag>
00558 >::type CaseListA;
00559 typedef typename meta::Switch<CaseListA, ErrorFlag>::type FlagA;
00560 typedef typename meta::TypeListGenerator
00561 <
00562 meta::SwitchCase<IsBScalarType::value, ScalarFlag>,
00563 meta::SwitchCase< meta::Or<IsBIndependentFactorType::value, IsBFactorType::value>::value, IndependentFactorOrFactorFlag>
00564 >::type CaseListB;
00565 typedef typename meta::Switch<CaseListB, ErrorFlag>::type FlagB;
00566 typedef binary::InplaceOperationWrapper<A, B, OP, FlagA, FlagB> OperationWrapperType;
00567
00568 public:
00569 static void op
00570 (
00571 A& a,
00572 const B& b,
00573 OP op
00574 ) {
00575 OperationWrapperType::op(a, b, op);
00576 }
00577 };
00578
00579 }
00580
00581 }
00582
00583 template<class A , class B , class C, class OP>
00584 inline void operateBinary
00585 (
00586 const A& a,
00587 const B& b ,
00588 C& c,
00589 OP op
00590 ) {
00591 functionwrapper::binary::OperationWrapperSelector<A, B, C, OP>::op(a, b, c, op);
00592 }
00593
00594 template<class A , class B, class OP>
00595 inline void operateBinary
00596 (
00597 A& a,
00598 const B& b ,
00599 OP op
00600 ) {
00601 functionwrapper::binary::InplaceOperationWrapperSelector<A, B, OP>::op(a, b, op);
00602 }
00603
00604 template<class A , class B , class OP>
00605 inline void operateUnary
00606 (
00607 const A& a,
00608 B& b,
00609 OP op
00610 ) {
00611 functionwrapper::unary::OperationWrapperSelector<A, B, OP>::op(a, b, op);
00612 }
00613
00614 template<class A, class OP>
00615 inline void operateUnary
00616 (
00617 A& a ,
00618 OP op
00619 ) {
00620 functionwrapper::unary::InplaceOperationWrapperSelector<A, OP>::op(a, op);
00621 }
00622
00624
00625 }
00626
00627 #endif // OPENGM_OPERATIONWRAPPER_HXX