evplus.cc 5.91 KB
Newer Older
David Speck's avatar
David Speck committed
1 2 3 4 5 6
// Copyright 03.07.2017, University of Freiburg,
// Author: David Speck <speckd>.

#include "evplus.h"
#include <meddly.h>
#include <meddly_expert.h>
David Speck's avatar
David Speck committed
7 8
#include <limits>
#include "userOperations.h"
David Speck's avatar
David Speck committed
9 10 11

const MEDDLY::binary_opname *USER_OPS::EVPLUS;

David Speck's avatar
David Speck committed
12
namespace USER_OPS {
David Speck's avatar
David Speck committed
13 14
class EVPlus;
class Plus_Opname;
David Speck's avatar
David Speck committed
15
}  // namespace USER_OPS
David Speck's avatar
David Speck committed
16

David Speck's avatar
David Speck committed
17 18
class USER_OPS::EVPlus : public MEDDLY::binary_operation {
 public:
David Speck's avatar
David Speck committed
19 20
  EVPlus(const MEDDLY::binary_opname *code, MEDDLY::expert_forest *arg1,
         MEDDLY::expert_forest *arg2, MEDDLY::expert_forest *res)
David Speck's avatar
David Speck committed
21
      : binary_operation(code, 4, 2, arg1, arg2, res) {
David Speck's avatar
David Speck committed
22 23 24
    can_commute = true;
  }

David Speck's avatar
David Speck committed
25
  bool isStaleEntry(const MEDDLY::node_handle *entry) {
David Speck's avatar
David Speck committed
26 27 28 29
    return arg1F->isStale(entry[1]) || arg2F->isStale(entry[3]) ||
           resF->isStale(entry[5]);
  }

David Speck's avatar
David Speck committed
30
  void discardEntry(const MEDDLY::node_handle *entryData) {
David Speck's avatar
David Speck committed
31 32 33 34 35
    arg1F->uncacheNode(entryData[1]);
    arg2F->uncacheNode(entryData[3]);
    resF->uncacheNode(entryData[5]);
  }

David Speck's avatar
David Speck committed
36
  void showEntry(MEDDLY::output &strm, const MEDDLY::node_handle *data) const {
David Speck's avatar
David Speck committed
37 38 39 40 41 42
    strm << "[" << getName() << "(<" << long(data[0]) << ":" << long(data[1])
         << ">, <" << long(data[2]) << ":" << long(data[3]) << ">): <"
         << long(data[4]) << ":" << long(data[5]) << ">]";
  }

  void computeDDEdge(const MEDDLY::dd_edge &ar1, const MEDDLY::dd_edge &ar2,
David Speck's avatar
David Speck committed
43
                     MEDDLY::dd_edge &res) {
David Speck's avatar
David Speck committed
44 45 46 47 48 49 50 51 52
    MEDDLY::node_handle result;
    float ev, aev, bev;
    ar1.getEdgeValue(aev);
    ar2.getEdgeValue(bev);
    compute(aev, ar1.getNode(), bev, ar2.getNode(), ev, result);
    res.set(result, ev);
  }

  void compute(float aev, MEDDLY::node_handle a, float bev,
David Speck's avatar
David Speck committed
53 54 55 56
               MEDDLY::node_handle b, float &cev, MEDDLY::node_handle &c) {
    // std::cout << "<" << aev << ", " << a << ">, " << "<" << bev << ", " << b
    // << "> " << std::endl;
    if (checkTerminals(aev, a, bev, b, cev, c)) return;
David Speck's avatar
David Speck committed
57

David Speck's avatar
David Speck committed
58 59
    float residual = aev + bev;  // remove for default PLUS
    aev = bev = 0;               // remove for default PLUS
David Speck's avatar
David Speck committed
60
    MEDDLY::compute_table::search_key *Key = findResult(aev, a, bev, b, cev, c);
David Speck's avatar
David Speck committed
61
    if (0 == Key) {
David Speck's avatar
David Speck committed
62
      // std::cout << "Cache hit" << std::endl;
David Speck's avatar
David Speck committed
63
      cev += residual;  // remove for default PLUS
David Speck's avatar
David Speck committed
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
      return;
    }
    // Get level information
    const int aLevel = arg1F->getNodeLevel(a);
    const int bLevel = arg2F->getNodeLevel(b);

    const int resultLevel = aLevel > bLevel ? aLevel : bLevel;
    const int resultSize = resF->getLevelSize(resultLevel);

    // Initialize result
    MEDDLY::unpacked_node *nb =
        MEDDLY::unpacked_node::newFull(resF, resultLevel, resultSize);

    // Initialize readers
    MEDDLY::unpacked_node *A =
        (aLevel < resultLevel)
            ? MEDDLY::unpacked_node::newRedundant(arg1F, resultLevel, 0, a,
                                                  true)
            : MEDDLY::unpacked_node::newFromNode(arg1F, a, true);

    MEDDLY::unpacked_node *B =
        (bLevel < resultLevel)
            ? MEDDLY::unpacked_node::newRedundant(arg2F, resultLevel, 0, b,
                                                  true)
            : MEDDLY::unpacked_node::newFromNode(arg2F, b, true);

    // do computation
David Speck's avatar
David Speck committed
91
    for (int i = 0; i < resultSize; i++) {
David Speck's avatar
David Speck committed
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
      float ev;
      MEDDLY::node_handle ed;
      compute(aev + A->ef(i), A->d(i), bev + B->ef(i), B->d(i), ev, ed);
      nb->d_ref(i) = ed;
      nb->setEdge(i, ev);
    }

    // cleanup
    MEDDLY::unpacked_node::recycle(B);
    MEDDLY::unpacked_node::recycle(A);

    // Reduce
    MEDDLY::node_handle cl;
    resF->createReducedNode(-1, nb, cev, cl);
    c = cl;

    // std::cout << a << "," << aev << " vs. " << b << "," << bev << " = " << c
    // << "," << cev << std::endl;

    // Add to CT
    saveResult(Key, a, b, cev, c);
David Speck's avatar
David Speck committed
113
    cev += residual;  // remove for default PLUS
David Speck's avatar
David Speck committed
114 115
  }

David Speck's avatar
David Speck committed
116
 protected:
David Speck's avatar
David Speck committed
117 118 119
  // Check if something is a terminal
  bool checkTerminals(float aev, MEDDLY::node_handle a, float bev,
                      MEDDLY::node_handle b, float &cev,
David Speck's avatar
David Speck committed
120 121
                      MEDDLY::node_handle &c) {
    if (a == -1 && b == -1) {
David Speck's avatar
David Speck committed
122 123 124 125 126
      c = -1;
      cev = aev + bev;
      return true;
    }
    // Case where one (or both) edge is infinity
David Speck's avatar
David Speck committed
127
    if (aev == INFTY || bev == INFTY) {
David Speck's avatar
David Speck committed
128 129 130 131 132
      c = -1;
      cev = INFTY;
      return true;
    }

David Speck's avatar
David Speck committed
133
    if (0 == a || 0 == b) {
David Speck's avatar
David Speck committed
134 135 136 137 138 139
      std::cout << "ERROR => Zero edge pointer in intersectionmax" << std::endl;
      return true;
    }
    return false;
  }

David Speck's avatar
David Speck committed
140 141 142
  MEDDLY::compute_table::search_key *findResult(
      float aev, MEDDLY::node_handle a, float bev, MEDDLY::node_handle b,
      float &cev, MEDDLY::node_handle &c) {
David Speck's avatar
David Speck committed
143 144 145
    MEDDLY::compute_table::search_key *CTsrch = useCTkey();
    MEDDLY_DCASSERT(CTsrch);
    CTsrch->reset();
David Speck's avatar
David Speck committed
146
    if (can_commute && a > b) {
David Speck's avatar
David Speck committed
147 148 149 150
      CTsrch->write(bev);
      CTsrch->writeNH(b);
      CTsrch->write(aev);
      CTsrch->writeNH(a);
David Speck's avatar
David Speck committed
151
    } else {
David Speck's avatar
David Speck committed
152 153 154 155 156 157
      CTsrch->write(aev);
      CTsrch->writeNH(a);
      CTsrch->write(bev);
      CTsrch->writeNH(b);
    }
    MEDDLY::compute_table::search_result &cacheFind = CT->find(CTsrch);
David Speck's avatar
David Speck committed
158
    if (!cacheFind) return CTsrch;
David Speck's avatar
David Speck committed
159 160 161 162 163 164 165
    cacheFind.read(cev);
    c = resF->linkNode(cacheFind.readNH());
    doneCTkey(CTsrch);
    return 0;
  }

  void saveResult(MEDDLY::compute_table::search_key *Key, MEDDLY::node_handle a,
David Speck's avatar
David Speck committed
166
                  MEDDLY::node_handle b, float cev, MEDDLY::node_handle c) {
David Speck's avatar
David Speck committed
167 168 169 170 171 172 173 174 175
    arg1F->cacheNode(a);
    arg2F->cacheNode(b);
    MEDDLY::compute_table::entry_builder &entry = CT->startNewEntry(Key);
    entry.writeResult(cev);
    entry.writeResultNH(resF->cacheNode(c));
    CT->addEntry();
  }
};

David Speck's avatar
David Speck committed
176 177
class USER_OPS::Plus_Opname : public MEDDLY::binary_opname {
 public:
David Speck's avatar
David Speck committed
178 179 180 181
  Plus_Opname() : binary_opname("EVPLUS") {}

  MEDDLY::binary_operation *buildOperation(MEDDLY::expert_forest *arg1,
                                           MEDDLY::expert_forest *arg2,
David Speck's avatar
David Speck committed
182
                                           MEDDLY::expert_forest *res) const {
David Speck's avatar
David Speck committed
183 184 185 186
    return new USER_OPS::EVPlus(this, arg1, arg2, res);
  }
};

David Speck's avatar
David Speck committed
187
void USER_OPS::initializePlus() {
David Speck's avatar
David Speck committed
188 189
  USER_OPS::EVPLUS = new USER_OPS::Plus_Opname();
}