<commit_before>#pragma once

#include "Graph.hpp"

template <typename Weight>
Weight min_cost_flow(Graph<Weight> &g, int s, int t, Flow f) {
  const int V = g.size();
  const Weight INF = 1e9;
  // const Weight eps = 1e-8;
  static vector<Weight> h(V, 0), dist(V, 0);
  static vector<int> prevv(V), preve(V);
  using P = pair<Weight, int>;
  Weight res = 0;
  while (f > 0) {
    priority_queue<P, vector<P>, greater<P>> que;
    fill(begin(dist), end(dist), INF);
    dist[s] = 0;
    que.push(P(0, s));
    while (!que.empty()) {
      P p = que.top(); que.pop();
      int v = p.second;
      if (dist[v] < p.first) continue;
      for (int i = 0; i < (int)g[v].size(); ++i) {
        const auto &e = g[v][i];
        if (e.cap <= 0) continue;
        if (dist[e.to] > dist[v] + e.cost + h[v] - h[e.to] /* + eps */) {
          dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
          prevv[e.to] = v;
          preve[e.to] = i;
          que.push(P(dist[e.to], e.to));
        }
      }
    }
    if (dist[t] == INF) return -1;
    for (int i = 0; i < V; ++i) {
      h[i] += dist[i];
    }

    Flow d = f;
    for (int v = t; v != s; v = prevv[v]) {
      d = min(d, g[prevv[v]][preve[v]].cap);
    }
    f -= d;
    res += d * h[t];
    for (int v = t; v != s; v = prevv[v]) {
      auto &e = g[prevv[v]][preve[v]];
      e.cap -= d;
      g[v][e.rev].cap += d;
    }
  }
  return res;
}

// Verified : AOJ GRL_6_B (Minimum Cost Flow)
/*
int main() {
  int V, E, F;
  cin >> V >> E >> F;
  Graph<int> g(V);
  while (E--) {
    int u, v, c, d;
    cin >> u >> v >> c >> d;
    add_edge(g, u, v, c, d);
  }
  cout << min_cost_flow(g, 0, V-1, F) << endl;
  return 0;
}
*/
<commit_msg>modify min_cost_flow<commit_after>#pragma once

#include "Graph.hpp"

template <typename Flow, typename Cost>
Cost min_cost_flow(FCGraph<Flow, Cost> &g, int s, int t, Flow f,
                   Cost inf, bool init = true) {
  const int V = g.size();
  // const Cost eps = 1e-8;
  static vector<Cost> h(V, 0), dist(V, 0);
  static vector<int> prevv(V), preve(V);
  if (init) {
    fill(begin(h), end(h), 0);
    fill(begin(dist), end(dist), 0);
    fill(begin(prevv), end(prevv), 0);
    fill(begin(preve), end(preve), 0);
  }
  using P = pair<Cost, int>;
  Cost res = 0;
  while (f > 0) {
    priority_queue<P, vector<P>, greater<P>> que;
    fill(begin(dist), end(dist), inf);
    dist[s] = 0;
    que.push(P(0, s));
    while (!que.empty()) {
      P p = que.top(); que.pop();
      int v = p.second;
      if (dist[v] < p.first) continue;
      for (int i = 0; i < (int)g[v].size(); ++i) {
        const auto &e = g[v][i];
        if (e.cap <= 0) continue;
        if (dist[e.to] > dist[v] + e.cost + h[v] - h[e.to] /* + eps */) {
          dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
          prevv[e.to] = v;
          preve[e.to] = i;
          que.push(P(dist[e.to], e.to));
        }
      }
    }
    if (dist[t] == inf) return -1;
    for (int i = 0; i < V; ++i) {
      h[i] += dist[i];
    }

    Flow d = f;
    for (int v = t; v != s; v = prevv[v]) {
      d = min(d, g[prevv[v]][preve[v]].cap);
    }
    f -= d;
    res += d * h[t];
    for (int v = t; v != s; v = prevv[v]) {
      auto &e = g[prevv[v]][preve[v]];
      e.cap -= d;
      g[v][e.rev].cap += d;
    }
  }
  return res;
}

// Verified : AOJ GRL_6_B (Minimum Cost Flow)
/*
int main() {
  int V, E, F;
  cin >> V >> E >> F;
  FCGraph<int, int> g(V);
  while (E--) {
    int u, v, c, d;
    cin >> u >> v >> c >> d;
    add_edge(g, u, v, c, d);
  }
  cout << min_cost_flow(g, 0, V-1, F, int(1e9)) << endl;
  return 0;
}
*/
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/address_list.h"
#include "net/base/host_resolver.h"
#include "net/base/net_errors.h"
#include "net/base/tcp_client_socket.h"
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"

//-----------------------------------------------------------------------------

namespace {

class TCPClientSocketTest : public testing::Test {
};

}  // namespace

//-----------------------------------------------------------------------------

TEST_F(TCPClientSocketTest, Connect) {
  net::AddressList addr;
  net::HostResolver resolver;
  TestCompletionCallback callback;

  int rv = resolver.Resolve("www.google.com", 80, &addr, NULL);
  EXPECT_EQ(rv, net::OK);

  net::TCPClientSocket sock(addr);

  EXPECT_FALSE(sock.IsConnected());

  rv = sock.Connect(&callback);
  if (rv != net::OK) {
    ASSERT_EQ(rv, net::ERR_IO_PENDING);

    rv = callback.WaitForResult();
    EXPECT_EQ(rv, net::OK);
  }

  EXPECT_TRUE(sock.IsConnected());

  sock.Disconnect();
  EXPECT_FALSE(sock.IsConnected());
}

TEST_F(TCPClientSocketTest, Read) {
  net::AddressList addr;
  net::HostResolver resolver;
  TestCompletionCallback callback;

  int rv = resolver.Resolve("www.google.com", 80, &addr, &callback);
  EXPECT_EQ(rv, net::ERR_IO_PENDING);

  rv = callback.WaitForResult();
  EXPECT_EQ(rv, net::OK);

  net::TCPClientSocket sock(addr);

  rv = sock.Connect(&callback);
  if (rv != net::OK) {
    ASSERT_EQ(rv, net::ERR_IO_PENDING);

    rv = callback.WaitForResult();
    EXPECT_EQ(rv, net::OK);
  }

  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
  rv = sock.Write(request_text, arraysize(request_text) - 1, &callback);
  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

  if (rv == net::ERR_IO_PENDING) {
    rv = callback.WaitForResult();
    EXPECT_EQ(rv, arraysize(request_text) - 1);
  }

  char buf[4096];
  for (;;) {
    rv = sock.Read(buf, sizeof(buf), &callback);
    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

    if (rv == net::ERR_IO_PENDING)
      rv = callback.WaitForResult();

    EXPECT_GE(rv, 0);
    if (rv <= 0)
      break;
  }
}

TEST_F(TCPClientSocketTest, Read_SmallChunks) {
  net::AddressList addr;
  net::HostResolver resolver;
  TestCompletionCallback callback;

  int rv = resolver.Resolve("www.google.com", 80, &addr, NULL);
  EXPECT_EQ(rv, net::OK);

  net::TCPClientSocket sock(addr);

  rv = sock.Connect(&callback);
  if (rv != net::OK) {
    ASSERT_EQ(rv, net::ERR_IO_PENDING);

    rv = callback.WaitForResult();
    EXPECT_EQ(rv, net::OK);
  }

  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
  rv = sock.Write(request_text, arraysize(request_text) - 1, &callback);
  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

  if (rv == net::ERR_IO_PENDING) {
    rv = callback.WaitForResult();
    EXPECT_EQ(rv, arraysize(request_text) - 1);
  }

  char buf[1];
  for (;;) {
    rv = sock.Read(buf, sizeof(buf), &callback);
    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

    if (rv == net::ERR_IO_PENDING)
      rv = callback.WaitForResult();

    EXPECT_GE(rv, 0);
    if (rv <= 0)
      break;
  }
}

TEST_F(TCPClientSocketTest, Read_Interrupted) {
  net::AddressList addr;
  net::HostResolver resolver;
  TestCompletionCallback callback;

  int rv = resolver.Resolve("www.google.com", 80, &addr, NULL);
  EXPECT_EQ(rv, net::OK);

  net::TCPClientSocket sock(addr);

  rv = sock.Connect(&callback);
  if (rv != net::OK) {
    ASSERT_EQ(rv, net::ERR_IO_PENDING);

    rv = callback.WaitForResult();
    EXPECT_EQ(rv, net::OK);
  }

  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
  rv = sock.Write(request_text, arraysize(request_text) - 1, &callback);
  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

  if (rv == net::ERR_IO_PENDING) {
    rv = callback.WaitForResult();
    EXPECT_EQ(rv, arraysize(request_text) - 1);
  }

  // Do a partial read and then exit.  This test should not crash!
  char buf[512];
  rv = sock.Read(buf, sizeof(buf), &callback);
  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

  if (rv == net::ERR_IO_PENDING)
    rv = callback.WaitForResult();

  EXPECT_NE(rv, 0);
}

<commit_msg>Avoid signedness mismatch errors from gcc<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/address_list.h"
#include "net/base/host_resolver.h"
#include "net/base/net_errors.h"
#include "net/base/tcp_client_socket.h"
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"

//-----------------------------------------------------------------------------

namespace {

class TCPClientSocketTest : public testing::Test {
};

}  // namespace

//-----------------------------------------------------------------------------

TEST_F(TCPClientSocketTest, Connect) {
  net::AddressList addr;
  net::HostResolver resolver;
  TestCompletionCallback callback;

  int rv = resolver.Resolve("www.google.com", 80, &addr, NULL);
  EXPECT_EQ(rv, net::OK);

  net::TCPClientSocket sock(addr);

  EXPECT_FALSE(sock.IsConnected());

  rv = sock.Connect(&callback);
  if (rv != net::OK) {
    ASSERT_EQ(rv, net::ERR_IO_PENDING);

    rv = callback.WaitForResult();
    EXPECT_EQ(rv, net::OK);
  }

  EXPECT_TRUE(sock.IsConnected());

  sock.Disconnect();
  EXPECT_FALSE(sock.IsConnected());
}

TEST_F(TCPClientSocketTest, Read) {
  net::AddressList addr;
  net::HostResolver resolver;
  TestCompletionCallback callback;

  int rv = resolver.Resolve("www.google.com", 80, &addr, &callback);
  EXPECT_EQ(rv, net::ERR_IO_PENDING);

  rv = callback.WaitForResult();
  EXPECT_EQ(rv, net::OK);

  net::TCPClientSocket sock(addr);

  rv = sock.Connect(&callback);
  if (rv != net::OK) {
    ASSERT_EQ(rv, net::ERR_IO_PENDING);

    rv = callback.WaitForResult();
    EXPECT_EQ(rv, net::OK);
  }

  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
  rv = sock.Write(request_text, arraysize(request_text) - 1, &callback);
  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

  if (rv == net::ERR_IO_PENDING) {
    rv = callback.WaitForResult();
    EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1));
  }

  char buf[4096];
  for (;;) {
    rv = sock.Read(buf, sizeof(buf), &callback);
    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

    if (rv == net::ERR_IO_PENDING)
      rv = callback.WaitForResult();

    EXPECT_GE(rv, 0);
    if (rv <= 0)
      break;
  }
}

TEST_F(TCPClientSocketTest, Read_SmallChunks) {
  net::AddressList addr;
  net::HostResolver resolver;
  TestCompletionCallback callback;

  int rv = resolver.Resolve("www.google.com", 80, &addr, NULL);
  EXPECT_EQ(rv, net::OK);

  net::TCPClientSocket sock(addr);

  rv = sock.Connect(&callback);
  if (rv != net::OK) {
    ASSERT_EQ(rv, net::ERR_IO_PENDING);

    rv = callback.WaitForResult();
    EXPECT_EQ(rv, net::OK);
  }

  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
  rv = sock.Write(request_text, arraysize(request_text) - 1, &callback);
  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

  if (rv == net::ERR_IO_PENDING) {
    rv = callback.WaitForResult();
    EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1));
  }

  char buf[1];
  for (;;) {
    rv = sock.Read(buf, sizeof(buf), &callback);
    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

    if (rv == net::ERR_IO_PENDING)
      rv = callback.WaitForResult();

    EXPECT_GE(rv, 0);
    if (rv <= 0)
      break;
  }
}

TEST_F(TCPClientSocketTest, Read_Interrupted) {
  net::AddressList addr;
  net::HostResolver resolver;
  TestCompletionCallback callback;

  int rv = resolver.Resolve("www.google.com", 80, &addr, NULL);
  EXPECT_EQ(rv, net::OK);

  net::TCPClientSocket sock(addr);

  rv = sock.Connect(&callback);
  if (rv != net::OK) {
    ASSERT_EQ(rv, net::ERR_IO_PENDING);

    rv = callback.WaitForResult();
    EXPECT_EQ(rv, net::OK);
  }

  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
  rv = sock.Write(request_text, arraysize(request_text) - 1, &callback);
  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

  if (rv == net::ERR_IO_PENDING) {
    rv = callback.WaitForResult();
    EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1));
  }

  // Do a partial read and then exit.  This test should not crash!
  char buf[512];
  rv = sock.Read(buf, sizeof(buf), &callback);
  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);

  if (rv == net::ERR_IO_PENDING)
    rv = callback.WaitForResult();

  EXPECT_NE(rv, 0);
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006-2020  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation (FSF), either version 3 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "vectorrealtotensor.h"

using namespace std;

namespace essentia {
namespace streaming {

const char* VectorRealToTensor::name = "VectorRealToTensor";
const char* VectorRealToTensor::category = "Standard";
const char* VectorRealToTensor::description = DOC("This algorithm generates tensors "
"out of a stream of input frames. The 4 dimensions of the tensors stand for (batchSize, channels, patchSize, featureSize):\n"
"  - batchSize: Number of patches per tensor. If batchSize is set to 0 it will accumulate patches until the end of the stream is reached and then produce a single tensor. "
"Warning: This option may exhaust memory depending on the size of the stream.\n"
"  - channels: Number of channels per tensor. Currently, only single-channel tensors are supported. Otherwise, an exception is thrown.\n"
"  - patchSize: Number of timestamps (i.e., number of frames) per patch.\n"
"  - featureSize: Expected number of features (e.g., mel bands) of every input frame. This algorithm throws an exception if the size of any frame is different from featureSize.\n"
"Additionally, the patchHopSize and batchHopSize parameters provide control over the amount of overlap on those dimensions.");

void VectorRealToTensor::configure() {
  vector<int> shape = parameter("shape").toVectorInt();
  _patchHopSize = parameter("patchHopSize").toInt();
  _batchHopSize = parameter("batchHopSize").toInt();
  _lastPatchMode = parameter("lastPatchMode").toString();

  _shape.resize(shape.size());
  for (size_t i = 0; i < shape.size(); i++) {
    if (shape[i] == 0) {
    throw EssentiaException("VectorRealToTensor: All dimensions should have a non-zero size.");
    }

    _shape[i] = shape[i];
  }

  if (shape[1] != 1) {
    throw EssentiaException("VectorRealToTensor: Currently only single-channel tensors are supported.");
  }

  _timeStamps = shape[2];
  _frame.setAcquireSize(_timeStamps);

  if (shape[0] == -1) {
    _accumulate = true;
  }

  if (_batchHopSize == 0) {
    _batchHopSize = shape[0];
  }

  if (_patchHopSize == 0) {
    _patchHopSize = _timeStamps;
  }

  _acc.assign(0, vector<vector<Real> >(_shape[2], vector<Real>(_shape[3], 0.0)));
  _push = false;

  if (_patchHopSize > _timeStamps) {
    throw EssentiaException("VectorRealToTensor: `patchHopSize` has to be smaller that the number of timestamps");
  }

  if (shape[0] > 0) {
    if (_batchHopSize > _timeStamps) {
      throw EssentiaException("VectorRealToTensor: `batchHopSize` has to be smaller that the number batch size (shape[0])");
    }
  }

}

AlgorithmStatus VectorRealToTensor::process() {
  EXEC_DEBUG("process()");
  if (_timeStamps != _frame.acquireSize()) {
    _frame.setAcquireSize(_timeStamps);
  }
  if (_patchHopSize != _frame.releaseSize()) {
    _frame.setReleaseSize(_patchHopSize);
  }

  // Check if we have enough frames to add a patch.
  int available = _frame.available();
  bool addPatch = (available >= _timeStamps);

  // If we should stop just take the remaining frames.
  if (shouldStop() && (available < _timeStamps)) {
    _frame.setAcquireSize(available);
    _frame.setReleaseSize(available);

    // Push if there are remaining frames
    if (_lastPatchMode == "repeat" && available > 0) {
      addPatch = true;
      _push = true;

    // or if we have been accumulating.
    } else if (_accumulate && _acc.size() >= 1) {
      addPatch = true;
      _push = true;
    }
  }

  // Return if there is nothing to do.
  if ((!addPatch) && (!_push)) return NO_INPUT;

  if (_push) {
    _tensor.setAcquireSize(1);
    _tensor.setReleaseSize(1);

    // Don't get frames if we just want to push.
    if (!addPatch) {
      _frame.setAcquireSize(0);
      _frame.setReleaseSize(0);
    }

  // Don't get a tensor if we are just accumulating.
  } else {
    _tensor.setAcquireSize(0);
    _tensor.setReleaseSize(0);
  }

  AlgorithmStatus status = acquireData();
  EXEC_DEBUG("data acquired (in: " << _frame.acquireSize()
            << " - out: " << _tensor.acquireSize() << ")");

  if (status != OK) {
    return status;
  };

  AlgorithmStatus outStatus = NO_OUTPUT;

  // Frames accumulation step.
  if (addPatch) {
    const vector<vector<Real> >& frame = _frame.tokens();

    // Sanity check.
    for (size_t i = 0; i < frame.size(); i++) {
      if ((int)frame[i].size() != _shape[3]) {
        throw EssentiaException("VectorRealToTensor: Found input frame with size ", frame[i].size(),
                                " while the algorithm was configured to work with frames with size ", _shape[3]);
      }
    }

    // Add a regular patch.
    if ((int)frame.size() == _timeStamps) {
      _acc.push_back(frame);

    // If size does not match rather repeat frames or discard them.
    } else {
      if (_lastPatchMode == "repeat") {
        if (frame.size() == 0) {
          EXEC_DEBUG("VectorRealToTensor: 0 frames remaining.");

        } else {
          vector<vector<Real> > padded_frame = frame;

          for (int i = 0; i < _timeStamps; i++) {
            padded_frame.push_back(frame[i % frame.size()]);
          }

          EXEC_DEBUG("VectorRealToTensor: Repeating the remaining " << frame.size() << " frames to make one last patch.");
          _acc.push_back(padded_frame);
        }

      } else if (_lastPatchMode == "discard") {
        EXEC_DEBUG("VectorRealToTensor: Discarding last frames");
      } else {
        throw EssentiaException("VectorRealToTensor: Incomplete patch found "
                                "before reaching the end of the stream. This is not supposed to happen");
      }
    }
  }

  // We only push if when we have filled the whole batch
  // or if we have reached the end of the stream in
  // accumulate mode.
  if (_push) {
    vector<int> shape = _shape;
    int batchHopSize = _batchHopSize;

    // If we have been accumulating we have to get the
    // tensor's shape from the current status of the
    // accumulator.
    if (_accumulate) {
      shape[0] = _acc.size();
      batchHopSize = _acc.size();

      if (_acc.size() == 0) {
        throw EssentiaException("VectorRealToTensor: The stream has finished without enough frames to "
                                "produce a patch of the desired size. Consider setting the `lastPatchMode` "
                                "parameter to `repeat` in order to produce a batch.");
      }
    }

    Tensor<Real>& tensor = *(Tensor<Real> *)_tensor.getFirstToken();
    tensor.resize(shape);

    // TODO: Add flag to swap frequency axis from 4 to 2.
    for (int i = 0; i < shape[0]; i++) {      // Batch axis
      for (int j = 0; j < shape[2]; j++) {    // Time axis
        for (int k = 0; k < shape[3]; k++) {  // Freq axis
          tensor(i, 0, j, k) = _acc[i][j][k];
        }
      }
    }

    // Empty the accumulator.
    _acc.erase(_acc.begin(), _acc.begin() + batchHopSize);

    _push = false;
    outStatus = OK;
  }

  // Check if we should push in the next process().
  if (!_accumulate) {
    if ((int)_acc.size() >= _shape[0]) _push = true;
  }

  EXEC_DEBUG("releasing");
  releaseData();
  EXEC_DEBUG("released");
  return outStatus;
}

void VectorRealToTensor::reset() {
  _acc.assign(0, vector<vector<Real> >(_shape[1], vector<Real>(_shape[2], 0.0)));
  _push = false;
}

} // namespace streaming
} // namespace essentia
<commit_msg>Add Warning to VectorRealToTensor<commit_after>/*
 * Copyright (C) 2006-2020  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation (FSF), either version 3 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "vectorrealtotensor.h"

using namespace std;

namespace essentia {
namespace streaming {

const char* VectorRealToTensor::name = "VectorRealToTensor";
const char* VectorRealToTensor::category = "Standard";
const char* VectorRealToTensor::description = DOC("This algorithm generates tensors "
"out of a stream of input frames. The 4 dimensions of the tensors stand for (batchSize, channels, patchSize, featureSize):\n"
"  - batchSize: Number of patches per tensor. If batchSize is set to 0 it will accumulate patches until the end of the stream is reached and then produce a single tensor. "
"Warning: This option may exhaust memory depending on the size of the stream.\n"
"  - channels: Number of channels per tensor. Currently, only single-channel tensors are supported. Otherwise, an exception is thrown.\n"
"  - patchSize: Number of timestamps (i.e., number of frames) per patch.\n"
"  - featureSize: Expected number of features (e.g., mel bands) of every input frame. This algorithm throws an exception if the size of any frame is different from featureSize.\n"
"Additionally, the patchHopSize and batchHopSize parameters provide control over the amount of overlap on those dimensions.");

void VectorRealToTensor::configure() {
  vector<int> shape = parameter("shape").toVectorInt();
  _patchHopSize = parameter("patchHopSize").toInt();
  _batchHopSize = parameter("batchHopSize").toInt();
  _lastPatchMode = parameter("lastPatchMode").toString();

  _shape.resize(shape.size());
  for (size_t i = 0; i < shape.size(); i++) {
    if (shape[i] == 0) {
    throw EssentiaException("VectorRealToTensor: All dimensions should have a non-zero size.");
    }

    _shape[i] = shape[i];
  }

  if (shape[1] != 1) {
    throw EssentiaException("VectorRealToTensor: Currently only single-channel tensors are supported.");
  }

  _timeStamps = shape[2];
  _frame.setAcquireSize(_timeStamps);

  if (shape[0] == -1) {
    _accumulate = true;
  }

  if (_batchHopSize == 0) {
    _batchHopSize = shape[0];
  }

  if (_patchHopSize == 0) {
    _patchHopSize = _timeStamps;
  }

  _acc.assign(0, vector<vector<Real> >(_shape[2], vector<Real>(_shape[3], 0.0)));
  _push = false;

  if (_patchHopSize > _timeStamps) {
    throw EssentiaException("VectorRealToTensor: `patchHopSize` has to be smaller that the number of timestamps");
  }

  if (shape[0] > 0) {
    if (_batchHopSize > _timeStamps) {
      throw EssentiaException("VectorRealToTensor: `batchHopSize` has to be smaller that the number batch size (shape[0])");
    }
  }

}

AlgorithmStatus VectorRealToTensor::process() {
  EXEC_DEBUG("process()");
  if (_timeStamps != _frame.acquireSize()) {
    _frame.setAcquireSize(_timeStamps);
  }
  if (_patchHopSize != _frame.releaseSize()) {
    _frame.setReleaseSize(_patchHopSize);
  }

  // Check if we have enough frames to add a patch.
  int available = _frame.available();
  bool addPatch = (available >= _timeStamps);

  // If we should stop just take the remaining frames.
  if (shouldStop() && (available < _timeStamps)) {
    _frame.setAcquireSize(available);
    _frame.setReleaseSize(available);

    // Push if there are remaining frames
    if (_lastPatchMode == "repeat" && available > 0) {
      addPatch = true;
      _push = true;

    // or if we have been accumulating.
    } else if (_accumulate && _acc.size() >= 1) {
      addPatch = true;
      _push = true;
    }
  }

  // Return if there is nothing to do.
  if ((!addPatch) && (!_push)) return NO_INPUT;

  if (_push) {
    _tensor.setAcquireSize(1);
    _tensor.setReleaseSize(1);

    // Don't get frames if we just want to push.
    if (!addPatch) {
      _frame.setAcquireSize(0);
      _frame.setReleaseSize(0);
    }

  // Don't get a tensor if we are just accumulating.
  } else {
    _tensor.setAcquireSize(0);
    _tensor.setReleaseSize(0);
  }

  AlgorithmStatus status = acquireData();
  EXEC_DEBUG("data acquired (in: " << _frame.acquireSize()
            << " - out: " << _tensor.acquireSize() << ")");

  if (status != OK) {
    return status;
  };

  AlgorithmStatus outStatus = NO_OUTPUT;

  // Frames accumulation step.
  if (addPatch) {
    const vector<vector<Real> >& frame = _frame.tokens();

    // Sanity check.
    for (size_t i = 0; i < frame.size(); i++) {
      if ((int)frame[i].size() != _shape[3]) {
        throw EssentiaException("VectorRealToTensor: Found input frame with size ", frame[i].size(),
                                " while the algorithm was configured to work with frames with size ", _shape[3]);
      }
    }

    // Add a regular patch.
    if ((int)frame.size() == _timeStamps) {
      _acc.push_back(frame);

    // If size does not match rather repeat frames or discard them.
    } else {
      if (_lastPatchMode == "repeat") {
        if (frame.size() == 0) {
          EXEC_DEBUG("VectorRealToTensor: 0 frames remaining.");

        } else {
          if (frame.size() < 10) {
            E_WARNING("VectorRealToTensor: Last patch produced by repeating the last " << frame.size() << " frames. May result in unreliable predictions.");
          }
          vector<vector<Real> > padded_frame = frame;

          for (int i = 0; i < _timeStamps; i++) {
            padded_frame.push_back(frame[i % frame.size()]);
          }

          EXEC_DEBUG("VectorRealToTensor: Repeating the remaining " << frame.size() << " frames to make one last patch.");
          _acc.push_back(padded_frame);
        }

      } else if (_lastPatchMode == "discard") {
        EXEC_DEBUG("VectorRealToTensor: Discarding last frames");

      } else {
        throw EssentiaException("VectorRealToTensor: Incomplete patch found "
                                "before reaching the end of the stream. This is not supposed to happen");
      }
    }
  }

  // We only push if when we have filled the whole batch
  // or if we have reached the end of the stream in
  // accumulate mode.
  if (_push) {
    vector<int> shape = _shape;
    int batchHopSize = _batchHopSize;

    // If we have been accumulating we have to get the
    // tensor's shape from the current status of the
    // accumulator.
    if (_accumulate) {
      shape[0] = _acc.size();
      batchHopSize = _acc.size();

      if (_acc.size() == 0) {
        throw EssentiaException("VectorRealToTensor: The stream has finished without enough frames to "
                                "produce a patch of the desired size. Consider setting the `lastPatchMode` "
                                "parameter to `repeat` in order to produce a batch.");
      }
    }

    Tensor<Real>& tensor = *(Tensor<Real> *)_tensor.getFirstToken();
    tensor.resize(shape);

    // TODO: Add flag to swap frequency axis from 4 to 2.
    for (int i = 0; i < shape[0]; i++) {      // Batch axis
      for (int j = 0; j < shape[2]; j++) {    // Time axis
        for (int k = 0; k < shape[3]; k++) {  // Freq axis
          tensor(i, 0, j, k) = _acc[i][j][k];
        }
      }
    }

    // Empty the accumulator.
    _acc.erase(_acc.begin(), _acc.begin() + batchHopSize);

    _push = false;
    outStatus = OK;
  }

  // Check if we should push in the next process().
  if (!_accumulate) {
    if ((int)_acc.size() >= _shape[0]) _push = true;
  }

  EXEC_DEBUG("releasing");
  releaseData();
  EXEC_DEBUG("released");
  return outStatus;
}

void VectorRealToTensor::reset() {
  _acc.assign(0, vector<vector<Real> >(_shape[1], vector<Real>(_shape[2], 0.0)));
  _push = false;
}

} // namespace streaming
} // namespace essentia
<|endoftext|>


<commit_before>// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "FrameBufferX11.hpp"

#include "libX11.hpp"
#include "Common/Timer.hpp"

#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

namespace sw
{
	static int (*PreviousXErrorHandler)(Display *display, XErrorEvent *event) = 0;
	static bool shmBadAccess = false;

	// Catches BadAcces errors so we can fall back to not using MIT-SHM
	static int XShmErrorHandler(Display *display, XErrorEvent *event)
	{
		if(event->error_code == BadAccess)
		{
			shmBadAccess = true;
			return 0;
		}
		else
		{
			return PreviousXErrorHandler(display, event);
		}
	}

	FrameBufferX11::FrameBufferX11(Display *display, Window window, int width, int height) : FrameBuffer(width, height, false, false), ownX11(!display), x_display(display), x_window(window)
	{
		if(!x_display)
		{
			x_display = libX11->XOpenDisplay(0);
			assert(x_display);
		}

		XWindowAttributes attribs;
		Status status = libX11->XGetWindowAttributes(display, window, &attribs);
		assert(status == 0);
		int depth = attribs.depth;
		Visual *visual = attribs.visual;

		x_gc = libX11->XCreateGC(x_display, window, 0, nullptr);

		mit_shm = (libX11->XShmQueryExtension && libX11->XShmQueryExtension(x_display) == True);
		if(mit_shm)
		{
			x_image = libX11->XShmCreateImage(x_display, visual, depth, ZPixmap, 0, &shminfo, width, height);

			shminfo.shmid = shmget(IPC_PRIVATE, x_image->bytes_per_line * x_image->height, IPC_CREAT | SHM_R | SHM_W);
			shminfo.shmaddr = x_image->data = (char*)shmat(shminfo.shmid, 0, 0);
			shminfo.readOnly = False;

			PreviousXErrorHandler = libX11->XSetErrorHandler(XShmErrorHandler);
			libX11->XShmAttach(x_display, &shminfo);   // May produce a BadAccess error
			libX11->XSync(x_display, False);
			libX11->XSetErrorHandler(PreviousXErrorHandler);

			if(shmBadAccess)
			{
				mit_shm = false;

				XDestroyImage(x_image);
				shmdt(shminfo.shmaddr);
				shmctl(shminfo.shmid, IPC_RMID, 0);

				shmBadAccess = false;
			}
		}

		if(!mit_shm)
		{
			int bytes_per_line = width * 4;
			int bytes_per_image = height * bytes_per_line;
			char *buffer = (char*)malloc(bytes_per_image);
			memset(buffer, 0, bytes_per_image);

			x_image = libX11->XCreateImage(x_display, visual, depth, ZPixmap, 0, buffer, width, height, 32, bytes_per_line);
			assert(x_image);

			if(!x_image)
			{
				free(buffer);
			}
		}
	}

	FrameBufferX11::~FrameBufferX11()
	{
		if(x_gc)
		{
			libX11->XFreeGC(x_display, x_gc);
		}

		if(!mit_shm)
		{
			XDestroyImage(x_image);
		}
		else
		{
			libX11->XShmDetach(x_display, &shminfo);
			XDestroyImage(x_image);
			shmdt(shminfo.shmaddr);
			shmctl(shminfo.shmid, IPC_RMID, 0);
		}

		if(ownX11)
		{
			libX11->XCloseDisplay(x_display);
		}
	}

	void *FrameBufferX11::lock()
	{
		if(x_image)
		{
			stride = x_image->bytes_per_line;
			framebuffer = x_image->data;
		}

		return framebuffer;
	}

	void FrameBufferX11::unlock()
	{
		framebuffer = nullptr;
	}

	void FrameBufferX11::blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
	{
		copy(source);

		if(!mit_shm)
		{
			libX11->XPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height);
		}
		else
		{
			libX11->XShmPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height, False);
		}

		libX11->XSync(x_display, False);

		if(false)   // Draw the framerate on screen
		{
			static double fpsTime = sw::Timer::seconds();
			static int frames = -1;

			double time = sw::Timer::seconds();
			double delta = time - fpsTime;
			frames++;

			static double FPS = 0.0;
			static double maxFPS = 0.0;

			if(delta > 1.0)
			{
				FPS = frames / delta;

				fpsTime = time;
				frames = 0;

				if(FPS > maxFPS)
				{
					maxFPS = FPS;
				}
			}

			char string[256];
			sprintf(string, "FPS: %.2f (max: %.2f)", FPS, maxFPS);
			libX11->XDrawString(x_display, x_window, x_gc, 50, 50, string, strlen(string));
		}
	}
}

// Chromium can be built with USE_X11 && USE_OZONE. In case of pure USE_X11 builds, we can use this path.
// In another case, the decision what framebuffer to create will be done by the FrameBufferFactoryOzone.
#if !defined(USE_OZONE)
NO_SANITIZE_FUNCTION sw::FrameBuffer *createFrameBuffer(void *display, Window window, int width, int height)
{
	return new sw::FrameBufferX11((::Display*)display, window, width, height);
}
#endif
<commit_msg>Convert failing assert condition<commit_after>// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "FrameBufferX11.hpp"

#include "libX11.hpp"
#include "Common/Timer.hpp"

#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

namespace sw
{
	static int (*PreviousXErrorHandler)(Display *display, XErrorEvent *event) = 0;
	static bool shmBadAccess = false;

	// Catches BadAcces errors so we can fall back to not using MIT-SHM
	static int XShmErrorHandler(Display *display, XErrorEvent *event)
	{
		if(event->error_code == BadAccess)
		{
			shmBadAccess = true;
			return 0;
		}
		else
		{
			return PreviousXErrorHandler(display, event);
		}
	}

	FrameBufferX11::FrameBufferX11(Display *display, Window window, int width, int height) : FrameBuffer(width, height, false, false), ownX11(!display), x_display(display), x_window(window)
	{
		if(!x_display)
		{
			x_display = libX11->XOpenDisplay(0);
			assert(x_display);
		}

		XWindowAttributes attribs;
		Status status = libX11->XGetWindowAttributes(display, window, &attribs);
		assert(status != 0);
		int depth = attribs.depth;
		Visual *visual = attribs.visual;

		x_gc = libX11->XCreateGC(x_display, window, 0, nullptr);

		mit_shm = (libX11->XShmQueryExtension && libX11->XShmQueryExtension(x_display) == True);
		if(mit_shm)
		{
			x_image = libX11->XShmCreateImage(x_display, visual, depth, ZPixmap, 0, &shminfo, width, height);

			shminfo.shmid = shmget(IPC_PRIVATE, x_image->bytes_per_line * x_image->height, IPC_CREAT | SHM_R | SHM_W);
			shminfo.shmaddr = x_image->data = (char*)shmat(shminfo.shmid, 0, 0);
			shminfo.readOnly = False;

			PreviousXErrorHandler = libX11->XSetErrorHandler(XShmErrorHandler);
			libX11->XShmAttach(x_display, &shminfo);   // May produce a BadAccess error
			libX11->XSync(x_display, False);
			libX11->XSetErrorHandler(PreviousXErrorHandler);

			if(shmBadAccess)
			{
				mit_shm = false;

				XDestroyImage(x_image);
				shmdt(shminfo.shmaddr);
				shmctl(shminfo.shmid, IPC_RMID, 0);

				shmBadAccess = false;
			}
		}

		if(!mit_shm)
		{
			int bytes_per_line = width * 4;
			int bytes_per_image = height * bytes_per_line;
			char *buffer = (char*)malloc(bytes_per_image);
			memset(buffer, 0, bytes_per_image);

			x_image = libX11->XCreateImage(x_display, visual, depth, ZPixmap, 0, buffer, width, height, 32, bytes_per_line);
			assert(x_image);

			if(!x_image)
			{
				free(buffer);
			}
		}
	}

	FrameBufferX11::~FrameBufferX11()
	{
		if(x_gc)
		{
			libX11->XFreeGC(x_display, x_gc);
		}

		if(!mit_shm)
		{
			XDestroyImage(x_image);
		}
		else
		{
			libX11->XShmDetach(x_display, &shminfo);
			XDestroyImage(x_image);
			shmdt(shminfo.shmaddr);
			shmctl(shminfo.shmid, IPC_RMID, 0);
		}

		if(ownX11)
		{
			libX11->XCloseDisplay(x_display);
		}
	}

	void *FrameBufferX11::lock()
	{
		if(x_image)
		{
			stride = x_image->bytes_per_line;
			framebuffer = x_image->data;
		}

		return framebuffer;
	}

	void FrameBufferX11::unlock()
	{
		framebuffer = nullptr;
	}

	void FrameBufferX11::blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
	{
		copy(source);

		if(!mit_shm)
		{
			libX11->XPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height);
		}
		else
		{
			libX11->XShmPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height, False);
		}

		libX11->XSync(x_display, False);

		if(false)   // Draw the framerate on screen
		{
			static double fpsTime = sw::Timer::seconds();
			static int frames = -1;

			double time = sw::Timer::seconds();
			double delta = time - fpsTime;
			frames++;

			static double FPS = 0.0;
			static double maxFPS = 0.0;

			if(delta > 1.0)
			{
				FPS = frames / delta;

				fpsTime = time;
				frames = 0;

				if(FPS > maxFPS)
				{
					maxFPS = FPS;
				}
			}

			char string[256];
			sprintf(string, "FPS: %.2f (max: %.2f)", FPS, maxFPS);
			libX11->XDrawString(x_display, x_window, x_gc, 50, 50, string, strlen(string));
		}
	}
}

// Chromium can be built with USE_X11 && USE_OZONE. In case of pure USE_X11 builds, we can use this path.
// In another case, the decision what framebuffer to create will be done by the FrameBufferFactoryOzone.
#if !defined(USE_OZONE)
NO_SANITIZE_FUNCTION sw::FrameBuffer *createFrameBuffer(void *display, Window window, int width, int height)
{
	return new sw::FrameBufferX11((::Display*)display, window, width, height);
}
#endif
<|endoftext|>


<commit_before>/*
 * opencog/atoms/reduct/ArithmeticLink.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <limits>

#include <opencog/atoms/base/atom_types.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/core/NumberNode.h>
#include "ArithmeticLink.h"

using namespace opencog;

ArithmeticLink::ArithmeticLink(const HandleSeq& oset, Type t)
    : FoldLink(oset, t)
{
	init();
}

ArithmeticLink::ArithmeticLink(Type t, const Handle& a, const Handle& b)
    : FoldLink(t, a, b)
{
	init();
}

ArithmeticLink::ArithmeticLink(const Link& l)
    : FoldLink(l)
{
	init();
}

void ArithmeticLink::init(void)
{
	Type tscope = get_type();
	if (not classserver().isA(tscope, ARITHMETIC_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a ArithmeticLink");

	knild = std::numeric_limits<double>::quiet_NaN();
}

// ===========================================================
/// reduce() -- reduce the expression by summing constants, etc.
///
/// No actual black-box evaluation or execution is performed. Only
/// clearbox reductions are performed.
///
/// Examples: the reduct of (PlusLink (NumberNode 2) (NumberNode 2))
/// is (NumberNode 4) -- its just a constant.
///
/// The reduct of (PlusLink (VariableNode "$x") (NumberNode 0)) is
/// (VariableNode "$x"), because adding zero to anything yeilds the
/// thing itself.
Handle ArithmeticLink::reduce(void)
{
	Handle road(reorder());
	ArithmeticLinkPtr alp(ArithmeticLinkCast(road));

	Handle red(alp->FoldLink::reduce());

	alp = ArithmeticLinkCast(red);
	if (NULL == alp) return red;
	return alp->reorder();
}

// ============================================================

/// re-order the contents of an ArithmeticLink into "lexicographic" order.
///
/// The goal of the re-ordering is to simplify the reduction code,
/// by placing atoms where they are easily found.  For now, this
/// means:
/// first, all of the variables,
/// next, all compound expressions,
/// last, all number nodes
/// We do not currently sort the variables, but maybe we should...?
/// Sorting by variable names would hold consilidate them...
/// The FoldLink::reduce() method already returns expressions that are
/// almost in the correct order.
Handle ArithmeticLink::reorder(void)
{
	HandleSeq vars;
	HandleSeq exprs;
	HandleSeq numbers;

	for (const Handle& h : _outgoing)
	{
		if (h->get_type() == VARIABLE_NODE)
			vars.push_back(h);
		else if (h->get_type() == NUMBER_NODE)
			numbers.push_back(h);
		else
			exprs.push_back(h);
	}

	HandleSeq result;
	for (const Handle& h : vars) result.push_back(h);
	for (const Handle& h : exprs) result.push_back(h);
	for (const Handle& h : numbers) result.push_back(h);

	Handle h(createLink(result, get_type()));
	if (NULL == _atom_space) return h;

	return _atom_space->add_atom(h);
}

// ===========================================================

/// execute() -- Execute the expression, returning a number
///
/// Similar to reduce(), above, except that this can only work
/// on fully grounded (closed) sentences: after executation,
/// everything must be a number, and there can be no variables
/// in sight.
static inline double get_double(AtomSpace *as, Handle h)
{
	NumberNodePtr nnn(NumberNodeCast(h));
	if (nnn == nullptr)
		throw RuntimeException(TRACE_INFO,
			  "Expecting a NumberNode, got %s",
		     classserver().getTypeName(h->get_type()).c_str());

	return nnn->get_value();
}

NumberNodePtr ArithmeticLink::unwrap_set(Handle h) const
{
	FunctionLinkPtr flp(FunctionLinkCast(h));
	if (flp) h = flp->execute();

	// Pattern matching hack. The pattern matcher returns sets of atoms;
	// if that set contains numbers or something numeric, then unwrap it.
	if (SET_LINK == h->get_type())
	{
		if (1 != h->get_arity())
			throw SyntaxException(TRACE_INFO,
				"Don't know how to do arithmetic with this: %s",
				h->to_string().c_str());
		h = h->getOutgoingAtom(0);
	}

	NumberNodePtr na(NumberNodeCast(h));
	if (nullptr == na)
		throw SyntaxException(TRACE_INFO,
			"Don't know how to do arithmetic with this: %s",
			h->to_string().c_str());
	return na;
}

Handle ArithmeticLink::execute(AtomSpace* as) const
{
	// Pattern matching hack. The pattern matcher returns sets of atoms;
	// if that set contains numbers or something numeric, then unwrap it.
	if (1 == _outgoing.size())
	{
		Handle arg = _outgoing[0];
		FunctionLinkPtr flp(FunctionLinkCast(arg));
		if (flp) arg = flp->execute(as);

		if (SET_LINK == arg->get_type())
		{
			return do_execute(as, arg->getOutgoingSet());
		}
		HandleSeq o;
		o.emplace_back(arg);
		return do_execute(as, o);
	}
	return do_execute(as, _outgoing);
}

Handle ArithmeticLink::do_execute(AtomSpace* as, const HandleSeq& oset) const
{
	double sum = knild;
	for (Handle h: oset)
	{
		h = unwrap_set(h);
		sum = konsd(sum, get_double(as, h));
	}

	if (as) return as->add_atom(createNumberNode(sum));
	return Handle(createNumberNode(sum));
}

// ===========================================================
<commit_msg>Minor ArithmeticLink::execute simplification<commit_after>/*
 * opencog/atoms/reduct/ArithmeticLink.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <limits>

#include <opencog/atoms/base/atom_types.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/core/NumberNode.h>
#include "ArithmeticLink.h"

using namespace opencog;

ArithmeticLink::ArithmeticLink(const HandleSeq& oset, Type t)
    : FoldLink(oset, t)
{
	init();
}

ArithmeticLink::ArithmeticLink(Type t, const Handle& a, const Handle& b)
    : FoldLink(t, a, b)
{
	init();
}

ArithmeticLink::ArithmeticLink(const Link& l)
    : FoldLink(l)
{
	init();
}

void ArithmeticLink::init(void)
{
	Type tscope = get_type();
	if (not classserver().isA(tscope, ARITHMETIC_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a ArithmeticLink");

	knild = std::numeric_limits<double>::quiet_NaN();
}

// ===========================================================
/// reduce() -- reduce the expression by summing constants, etc.
///
/// No actual black-box evaluation or execution is performed. Only
/// clearbox reductions are performed.
///
/// Examples: the reduct of (PlusLink (NumberNode 2) (NumberNode 2))
/// is (NumberNode 4) -- its just a constant.
///
/// The reduct of (PlusLink (VariableNode "$x") (NumberNode 0)) is
/// (VariableNode "$x"), because adding zero to anything yeilds the
/// thing itself.
Handle ArithmeticLink::reduce(void)
{
	Handle road(reorder());
	ArithmeticLinkPtr alp(ArithmeticLinkCast(road));

	Handle red(alp->FoldLink::reduce());

	alp = ArithmeticLinkCast(red);
	if (NULL == alp) return red;
	return alp->reorder();
}

// ============================================================

/// re-order the contents of an ArithmeticLink into "lexicographic" order.
///
/// The goal of the re-ordering is to simplify the reduction code,
/// by placing atoms where they are easily found.  For now, this
/// means:
/// first, all of the variables,
/// next, all compound expressions,
/// last, all number nodes
/// We do not currently sort the variables, but maybe we should...?
/// Sorting by variable names would hold consilidate them...
/// The FoldLink::reduce() method already returns expressions that are
/// almost in the correct order.
Handle ArithmeticLink::reorder(void)
{
	HandleSeq vars;
	HandleSeq exprs;
	HandleSeq numbers;

	for (const Handle& h : _outgoing)
	{
		if (h->get_type() == VARIABLE_NODE)
			vars.push_back(h);
		else if (h->get_type() == NUMBER_NODE)
			numbers.push_back(h);
		else
			exprs.push_back(h);
	}

	HandleSeq result;
	for (const Handle& h : vars) result.push_back(h);
	for (const Handle& h : exprs) result.push_back(h);
	for (const Handle& h : numbers) result.push_back(h);

	Handle h(createLink(result, get_type()));
	if (NULL == _atom_space) return h;

	return _atom_space->add_atom(h);
}

// ===========================================================

/// execute() -- Execute the expression, returning a number
///
/// Similar to reduce(), above, except that this can only work
/// on fully grounded (closed) sentences: after executation,
/// everything must be a number, and there can be no variables
/// in sight.
static inline double get_double(AtomSpace *as, Handle h)
{
	NumberNodePtr nnn(NumberNodeCast(h));
	if (nnn == nullptr)
		throw RuntimeException(TRACE_INFO,
			  "Expecting a NumberNode, got %s",
		     classserver().getTypeName(h->get_type()).c_str());

	return nnn->get_value();
}

NumberNodePtr ArithmeticLink::unwrap_set(Handle h) const
{
	FunctionLinkPtr flp(FunctionLinkCast(h));
	if (flp) h = flp->execute();

	// Pattern matching hack. The pattern matcher returns sets of atoms;
	// if that set contains numbers or something numeric, then unwrap it.
	if (SET_LINK == h->get_type())
	{
		if (1 != h->get_arity())
			throw SyntaxException(TRACE_INFO,
				"Don't know how to do arithmetic with this: %s",
				h->to_string().c_str());
		h = h->getOutgoingAtom(0);
	}

	NumberNodePtr na(NumberNodeCast(h));
	if (nullptr == na)
		throw SyntaxException(TRACE_INFO,
			"Don't know how to do arithmetic with this: %s",
			h->to_string().c_str());
	return na;
}

Handle ArithmeticLink::execute(AtomSpace* as) const
{
	// Pattern matching hack. The pattern matcher returns sets of atoms;
	// if that set contains numbers or something numeric, then unwrap it.
	if (1 == _outgoing.size())
	{
		Handle arg = _outgoing[0];
		FunctionLinkPtr flp(FunctionLinkCast(arg));
		if (flp) arg = flp->execute(as);

		if (SET_LINK == arg->get_type())
		{
			return do_execute(as, arg->getOutgoingSet());
		}
		return do_execute(as, {arg});
	}
	return do_execute(as, _outgoing);
}

Handle ArithmeticLink::do_execute(AtomSpace* as, const HandleSeq& oset) const
{
	double sum = knild;
	for (Handle h: oset)
	{
		h = unwrap_set(h);
		sum = konsd(sum, get_double(as, h));
	}

	if (as) return as->add_atom(createNumberNode(sum));
	return Handle(createNumberNode(sum));
}

// ===========================================================
<|endoftext|>


<commit_before>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <Onsang/utility.hpp>
#include <Onsang/UI/Defs.hpp>
#include <Onsang/UI/BasicGrid.hpp>
#include <Onsang/App.hpp>

#include <duct/debug.hpp>

namespace Onsang {
namespace UI {

void
BasicGrid::reflow_impl(
	Rect const& area,
	bool const cache
) noexcept {
	base::reflow_impl(area, cache);
	reflow_view(get_geometry().get_frame());
	adjust_view();
	queue_header_render();
	queue_cell_render(0, get_row_count());
	queue_actions(
		UI::UpdateActions::render |
		UI::UpdateActions::flag_noclear
	);
}

bool
BasicGrid::handle_event_impl(
	UI::Event const& event
) noexcept {
	switch (event.type) {
	case UI::EventType::key_input:
		if (!has_input_control()) {
			bool handled = true;
			switch (event.key_input.code) {
			case KeyCode::up   : row_step(-1); break;
			case KeyCode::down : row_step(+1); break;
			case KeyCode::left : col_step(-1); break;
			case KeyCode::right: col_step(+1); break;
			case KeyCode::home: row_abs(0); break;
			case KeyCode::end : row_abs(max_ce(0, get_row_count() - 1)); break;
			case KeyCode::pgup:
				row_step(min_ce(0, -get_view().fit_count - 1)); break;
			case KeyCode::pgdn:
				row_step(max_ce(0, +get_view().fit_count - 1)); break;

			default:
				switch (event.key_input.cp) {
				case 'k': row_step(-1); break;
				case 'j': row_step(+1); break;
				case 'h': col_step(-1); break;
				case 'l': col_step(+1); break;
				case 'a': select_all(); break;
				case 'A': select_none(); break;
				case 's': select_toggle(m_cursor.row, 1); break;
				//case 'e': erase(m_cursor.row, 1); break;
				//case 'E': erase_selected(); break;
				//case 'i': insert_after (m_cursor.row, 1); break;
				//case 'I': insert_before(m_cursor.row, 1); break;
				default:
					handled = false;
					break;
				}
			}
			return handled;
		}
		break;

	case UI::EventType::focus_changed:
		queue_cell_render(
			m_cursor.row, m_cursor.row + 1,
			m_cursor.col, m_cursor.col + 1
		);
		if (is_focused()) {
			App::instance.m_ui.csline->set_location(
				std::to_string(m_cursor.row) + ", " +
				std::to_string(m_cursor.col)
			);
		} else {
			App::instance.m_ui.csline->clear_location();
		}
		return false;

	default:
		break;
	}
	return false;
}

void
BasicGrid::render_impl(
	UI::Widget::RenderData& rd
) noexcept {
	UI::GridRenderData grid_rd{
		rd,
		is_focused(),
		is_focused()
	};
	render_view(
		grid_rd,
		!enum_cast(get_queued_actions() & UI::UpdateActions::flag_noclear)
	);

	auto const& view = get_view();
	Rect const empty_frame{
		{view.content_frame.pos.x, view.content_frame.pos.y + view.row_count},
		{
			view.content_frame.size.width,
			max_ce(0, view.fit_count - view.row_count)
		}
	};
	if (0 < empty_frame.size.height) {
		grid_rd.rd.terminal.clear_back(empty_frame);
		grid_rd.rd.terminal.put_line(
			empty_frame.pos,
			empty_frame.size.height,
			Axis::vertical,
			tty::make_cell('~',
				tty::Color::blue | tty::Attr::bold,
				tty::Color::term_default
			)
		);
	}
}

void
BasicGrid::content_action(
	UI::ProtoGrid::ContentAction action,
	UI::index_type row_begin,
	UI::index_type count
) noexcept {
	using CA = UI::ProtoGrid::ContentAction;

	DUCT_ASSERTE(get_row_count() == signed_cast(m_sel.size()));
	// Cast insert_after in terms of insert_before
	if (CA::insert_after == action) {
		++row_begin;
	}
	row_begin = value_clamp(row_begin, 0, get_row_count());
	auto const row_end = min_ce(row_begin + count, get_row_count());
	auto clear_flag = UI::UpdateActions::none;
	switch (action) {
	// Select
	case CA::select: // fall-through
	case CA::unselect: {
		bool const enable = CA::select == action;
		auto const end = m_sel.begin() + row_end;
		for (auto it = m_sel.begin() + row_begin; end > it; ++it) {
			*it = enable;
		}
		queue_cell_render(row_begin, row_end);
		clear_flag = UI::UpdateActions::flag_noclear;
	}	break;

	case CA::select_toggle: {
		auto const end = m_sel.begin() + row_end;
		for (auto it = m_sel.begin() + row_begin; end > it; ++it) {
			*it = !*it;
		}
		queue_cell_render(row_begin, row_end);
		clear_flag = UI::UpdateActions::flag_noclear;
	}	break;

	// Insert
	case CA::insert_after: // fall-through
	case CA::insert_before:
		for (UI::index_type i = 0; i < count; ++i) {
			if (content_insert(row_begin + i)) {
				m_sel.insert(m_sel.begin() + row_begin + i, false);
				content_action_internal(CA::insert_before, row_begin + i, 1);
			}
		}
		if (get_row_count() == 1) {
			set_cursor(m_cursor.col, 0);
		} else if (row_begin <= m_cursor.row) {
			set_cursor(m_cursor.col, m_cursor.row + count);
		}
		adjust_view();
		break;

	// Erase
	case CA::erase:
		for (UI::index_type i = 0; i < count; ++i) {
			if (content_erase(row_begin)) {
				m_sel.erase(m_sel.cbegin() + row_begin);
				content_action_internal(CA::erase, row_begin, 1);
			}
		}
		break;

	case CA::erase_selected:
		for (UI::index_type index = 0; index < get_row_count();) {
			if (m_sel[index] && content_erase(index)) {
				m_sel.erase(m_sel.cbegin() + index);
				content_action_internal(CA::erase, index, 1);
			} else {
				++index;
			}
		}
		break;
	} // switch (action)

	// Post action
	switch (action) {
	case CA::erase:
	case CA::erase_selected:
		// Let cursor clamp to new bounds
		set_cursor(m_cursor.col, m_cursor.row);
		adjust_view();
		break;

	default:
		break;
	}
	queue_actions(
		UI::UpdateActions::render |
		clear_flag
	);
}

void
BasicGrid::adjust_view() noexcept {
	auto const& view = get_view();
	if (
		view.row_range.x >  m_cursor.row ||
		view.row_range.y <= m_cursor.row ||
		view.col_range.x >  m_cursor.col ||
		view.col_range.y <= m_cursor.col
	) {
		auto row_begin = m_cursor.row;
		if (view.row_range.y <= m_cursor.row) {
			row_begin -= view.fit_count - 1;
		}
		update_view(
			row_begin,
			row_begin + view.fit_count,
			0,
			get_col_count(),
			true
		);
		queue_actions(UI::UpdateActions::render);
	}
}

void
BasicGrid::set_cursor(
	UI::index_type col,
	UI::index_type row
) noexcept {
	col = value_clamp(col, 0, max_ce(0, get_col_count() - 1));
	row = value_clamp(row, 0, max_ce(0, get_row_count() - 1));
	if (col != m_cursor.col || row != m_cursor.row) {
		if (
			value_in_bounds(m_cursor.row, 0, get_row_count()) &&
			value_in_bounds(m_cursor.col, 0, get_col_count())
		) {
			queue_cell_render(
				m_cursor.row, m_cursor.row + 1,
				m_cursor.col, m_cursor.col + 1
			);
		}
		if (get_row_count() > 0) {
			queue_cell_render(
				row, row + 1,
				col, col + 1
			);
		}
		queue_actions(
			UI::UpdateActions::render |
			UI::UpdateActions::flag_noclear
		);
		m_cursor.col = col;
		m_cursor.row = row;
		adjust_view();
		if (is_focused()) {
			App::instance.m_ui.csline->set_location(
				std::to_string(m_cursor.row) + ", " +
				std::to_string(m_cursor.col)
			);
		}
	}
}

void
BasicGrid::resize_grid(
	UI::index_type col_count,
	UI::index_type row_count
) {
	m_sel.resize(row_count);
	set_row_count(row_count);
	set_col_count(col_count);
	set_cursor(m_cursor.col, m_cursor.row);
	adjust_view();
	queue_actions(
		UI::UpdateActions::render
	);
}

} // namespace UI
} // namespace Onsang
<commit_msg>UI/BasicGrid: update view and queue full grid render in resize_grid().<commit_after>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <Onsang/utility.hpp>
#include <Onsang/UI/Defs.hpp>
#include <Onsang/UI/BasicGrid.hpp>
#include <Onsang/App.hpp>

#include <duct/debug.hpp>

namespace Onsang {
namespace UI {

void
BasicGrid::reflow_impl(
	Rect const& area,
	bool const cache
) noexcept {
	base::reflow_impl(area, cache);
	reflow_view(get_geometry().get_frame());
	adjust_view();
	queue_header_render();
	queue_cell_render(0, get_row_count());
	queue_actions(
		UI::UpdateActions::render |
		UI::UpdateActions::flag_noclear
	);
}

bool
BasicGrid::handle_event_impl(
	UI::Event const& event
) noexcept {
	switch (event.type) {
	case UI::EventType::key_input:
		if (!has_input_control()) {
			bool handled = true;
			switch (event.key_input.code) {
			case KeyCode::up   : row_step(-1); break;
			case KeyCode::down : row_step(+1); break;
			case KeyCode::left : col_step(-1); break;
			case KeyCode::right: col_step(+1); break;
			case KeyCode::home: row_abs(0); break;
			case KeyCode::end : row_abs(max_ce(0, get_row_count() - 1)); break;
			case KeyCode::pgup:
				row_step(min_ce(0, -get_view().fit_count - 1)); break;
			case KeyCode::pgdn:
				row_step(max_ce(0, +get_view().fit_count - 1)); break;

			default:
				switch (event.key_input.cp) {
				case 'k': row_step(-1); break;
				case 'j': row_step(+1); break;
				case 'h': col_step(-1); break;
				case 'l': col_step(+1); break;
				case 'a': select_all(); break;
				case 'A': select_none(); break;
				case 's': select_toggle(m_cursor.row, 1); break;
				//case 'e': erase(m_cursor.row, 1); break;
				//case 'E': erase_selected(); break;
				//case 'i': insert_after (m_cursor.row, 1); break;
				//case 'I': insert_before(m_cursor.row, 1); break;
				default:
					handled = false;
					break;
				}
			}
			return handled;
		}
		break;

	case UI::EventType::focus_changed:
		queue_cell_render(
			m_cursor.row, m_cursor.row + 1,
			m_cursor.col, m_cursor.col + 1
		);
		if (is_focused()) {
			App::instance.m_ui.csline->set_location(
				std::to_string(m_cursor.row) + ", " +
				std::to_string(m_cursor.col)
			);
		} else {
			App::instance.m_ui.csline->clear_location();
		}
		return false;

	default:
		break;
	}
	return false;
}

void
BasicGrid::render_impl(
	UI::Widget::RenderData& rd
) noexcept {
	UI::GridRenderData grid_rd{
		rd,
		is_focused(),
		is_focused()
	};
	render_view(
		grid_rd,
		!enum_cast(get_queued_actions() & UI::UpdateActions::flag_noclear)
	);

	auto const& view = get_view();
	Rect const empty_frame{
		{view.content_frame.pos.x, view.content_frame.pos.y + view.row_count},
		{
			view.content_frame.size.width,
			max_ce(0, view.fit_count - view.row_count)
		}
	};
	if (0 < empty_frame.size.height) {
		grid_rd.rd.terminal.clear_back(empty_frame);
		grid_rd.rd.terminal.put_line(
			empty_frame.pos,
			empty_frame.size.height,
			Axis::vertical,
			tty::make_cell('~',
				tty::Color::blue | tty::Attr::bold,
				tty::Color::term_default
			)
		);
	}
}

void
BasicGrid::content_action(
	UI::ProtoGrid::ContentAction action,
	UI::index_type row_begin,
	UI::index_type count
) noexcept {
	using CA = UI::ProtoGrid::ContentAction;

	DUCT_ASSERTE(get_row_count() == signed_cast(m_sel.size()));
	// Cast insert_after in terms of insert_before
	if (CA::insert_after == action) {
		++row_begin;
	}
	row_begin = value_clamp(row_begin, 0, get_row_count());
	auto const row_end = min_ce(row_begin + count, get_row_count());
	auto clear_flag = UI::UpdateActions::none;
	switch (action) {
	// Select
	case CA::select: // fall-through
	case CA::unselect: {
		bool const enable = CA::select == action;
		auto const end = m_sel.begin() + row_end;
		for (auto it = m_sel.begin() + row_begin; end > it; ++it) {
			*it = enable;
		}
		queue_cell_render(row_begin, row_end);
		clear_flag = UI::UpdateActions::flag_noclear;
	}	break;

	case CA::select_toggle: {
		auto const end = m_sel.begin() + row_end;
		for (auto it = m_sel.begin() + row_begin; end > it; ++it) {
			*it = !*it;
		}
		queue_cell_render(row_begin, row_end);
		clear_flag = UI::UpdateActions::flag_noclear;
	}	break;

	// Insert
	case CA::insert_after: // fall-through
	case CA::insert_before:
		for (UI::index_type i = 0; i < count; ++i) {
			if (content_insert(row_begin + i)) {
				m_sel.insert(m_sel.begin() + row_begin + i, false);
				content_action_internal(CA::insert_before, row_begin + i, 1);
			}
		}
		if (get_row_count() == 1) {
			set_cursor(m_cursor.col, 0);
		} else if (row_begin <= m_cursor.row) {
			set_cursor(m_cursor.col, m_cursor.row + count);
		}
		adjust_view();
		break;

	// Erase
	case CA::erase:
		for (UI::index_type i = 0; i < count; ++i) {
			if (content_erase(row_begin)) {
				m_sel.erase(m_sel.cbegin() + row_begin);
				content_action_internal(CA::erase, row_begin, 1);
			}
		}
		break;

	case CA::erase_selected:
		for (UI::index_type index = 0; index < get_row_count();) {
			if (m_sel[index] && content_erase(index)) {
				m_sel.erase(m_sel.cbegin() + index);
				content_action_internal(CA::erase, index, 1);
			} else {
				++index;
			}
		}
		break;
	} // switch (action)

	// Post action
	switch (action) {
	case CA::erase:
	case CA::erase_selected:
		// Let cursor clamp to new bounds
		set_cursor(m_cursor.col, m_cursor.row);
		adjust_view();
		break;

	default:
		break;
	}
	queue_actions(
		UI::UpdateActions::render |
		clear_flag
	);
}

void
BasicGrid::adjust_view() noexcept {
	auto const& view = get_view();
	if (
		view.row_range.x >  m_cursor.row ||
		view.row_range.y <= m_cursor.row ||
		view.col_range.x >  m_cursor.col ||
		view.col_range.y <= m_cursor.col
	) {
		auto row_begin = m_cursor.row;
		if (view.row_range.y <= m_cursor.row) {
			row_begin -= view.fit_count - 1;
		}
		update_view(
			row_begin,
			row_begin + view.fit_count,
			0,
			get_col_count(),
			true
		);
		queue_actions(UI::UpdateActions::render);
	}
}

void
BasicGrid::set_cursor(
	UI::index_type col,
	UI::index_type row
) noexcept {
	col = value_clamp(col, 0, max_ce(0, get_col_count() - 1));
	row = value_clamp(row, 0, max_ce(0, get_row_count() - 1));
	if (col != m_cursor.col || row != m_cursor.row) {
		if (
			value_in_bounds(m_cursor.row, 0, get_row_count()) &&
			value_in_bounds(m_cursor.col, 0, get_col_count())
		) {
			queue_cell_render(
				m_cursor.row, m_cursor.row + 1,
				m_cursor.col, m_cursor.col + 1
			);
		}
		if (get_row_count() > 0) {
			queue_cell_render(
				row, row + 1,
				col, col + 1
			);
		}
		queue_actions(
			UI::UpdateActions::render |
			UI::UpdateActions::flag_noclear
		);
		m_cursor.col = col;
		m_cursor.row = row;
		adjust_view();
		if (is_focused()) {
			App::instance.m_ui.csline->set_location(
				std::to_string(m_cursor.row) + ", " +
				std::to_string(m_cursor.col)
			);
		}
	}
}

void
BasicGrid::resize_grid(
	UI::index_type col_count,
	UI::index_type row_count
) {
	m_sel.resize(row_count);
	set_row_count(row_count);
	set_col_count(col_count);
	set_cursor(0, 0);
	update_view(
		0, get_view().fit_count,
		0, get_col_count(),
		false
	);
	queue_header_render();
	queue_cell_render(0, get_row_count());
	queue_actions(
		UI::UpdateActions::render
	);
}

} // namespace UI
} // namespace Onsang
<|endoftext|>


<commit_before>/*

sl_exchange5.cc

3 spin simulation with exchange in Hilbert space

*/

#include "gamma.h"
//#include <sys/time.h>
//#include <sys/resource.h>

#define NPROP 1000
#define MAXSPINS 3

using namespace std;

int main(int argc, char *argv[])

{
  sys_dynamic ax;
  gen_op Hrf,Ham, H[5], sigma, sigma1, detect[MAXSPINS];
  super_op Iop,K,L,U[NPROP],UT;
  spin_T  Hdip[MAXSPINS][MAXSPINS];
  space_T Adip[MAXSPINS][MAXSPINS], Adip_R[MAXSPINS][MAXSPINS];
  double D[MAXSPINS][MAXSPINS];
  double iso_CSA[MAXSPINS];
  int i,j,k,k1,k2,Fnp,count,qu,steps,nrotor;
  string name, names;
  const double thetam=54.73561032;
  double mas_freq,gamB1;
  double ltime, time, time_prop, scale;
  int nstart, nspins, index, nprop;
  double alpha,beta,gamma;
  double alpha_D[MAXSPINS][MAXSPINS],beta_D[MAXSPINS][MAXSPINS];
  double gamma_D[MAXSPINS][MAXSPINS];
  double tauc, kex;
  //struct rusage me;
  //struct timeval tp;

  int value1[] = {1, 50, 100, 144, 200, 300, 538, 1154};
  int value2[] = {1,  7,  27,  11,  29,  37,  55,  107};
  int value3[] = {1, 11,  41,  53,  79,  61, 229,  271};

/*initialize the random number generator*/
  //gettimeofday(&tp,NULL);
  //srand48(tp.tv_usec);
  enable_blockdiag();

  count = 1;
  query_parameter(argc,argv,count++,"Spin System Name            ? ", names);
//setup for the spin system
  ax.read(names);
  nspins = ax.spins();
  if(nspins != 3)
  { cerr << "This program is written for a MAXSPINS spin system.\n";
    cerr << "Please change your spin system definition in \n";
    cerr << "the file " << names << ".\n";
    cerr << "Aborting ....\n\n";
    exit(-1);
  }
  for(i=0;i<2;++i)
  { for(j=i+1;j<3;++j)
    { query_parameter(argc,argv,count++,"Dipolar Coupling Constant   ? ", D[i][j]);
      query_parameter(argc,argv,count++,"Euler angle alpha           ? ", alpha_D[i][j]);
      query_parameter(argc,argv,count++,"Euler angle beta            ? ", beta_D[i][j]);
      query_parameter(argc,argv,count++,"Euler angle gamma           ? ", gamma_D[i][j]);
    }
  }
  for(i=0;i<3;++i)
  { query_parameter(argc,argv,count++,"Isotropic chemical shift    ? ", iso_CSA[i]);
  }
  query_parameter(argc,argv,count++,"Powder Quality (cheng)      ? ", qu);
  query_parameter(argc,argv,count++,"Number of time steps        ? ", steps);
  query_parameter(argc,argv,count++,"spinning speed              ? ", mas_freq);
  query_parameter(argc,argv,count++,"Number of rotor periods     ? ", nrotor);
  query_parameter(argc,argv,count++,"Number of sampling per rotor? ", nprop);
  query_parameter(argc,argv,count++,"Initial density operator    ? ", nstart);
  query_parameter(argc,argv,count++,"jump correlation time       ? ", tauc);
  query_parameter(argc,argv,count++,"rf-field amplitude          ? ", gamB1);
  query_parameter(argc,argv,count++,"Output Filename             ? ", name);

  if(nstart >= nspins)
  { cerr << "The starting density operator has a spin number which is\n";
    cerr << "larger than the number of spins.\n";
    cerr << "Aborting ....\n\n";
    exit(-1);
  }

  Fnp = nprop*nrotor;

  time_prop  = (1.0/mas_freq)/nprop;
  time       = (1.0/mas_freq)/steps;
  kex        =1.0/(2.0*tauc);

  cout << "\n\nSimulation of isotropic chemical shift by dipolar coupling\n";
  cout << "==========================================================\n\n";
  cout << "Parameters:\n";
  cout << "rotation angle thetam          : " << thetam << " Degree\n";
  cout << "size of spin system            : " << nspins << " spins\n";
  cout << "initial density operator       : Ix(ax," << nstart << ")\n";
  for(i=0;i<2;++i)
  { for(j=i+1;j<3;++j)
    { cout << "dipolar coupling constant (" << i << "," << j << ") : " <<
              D[i][j] << " Hz\n";
      cout << "relativ orientation of D tensor: (" << alpha_D[i][j] << "," <<
               beta_D[i][j] << "," << gamma_D[i][j] << ")\n";
    }
  }
  for(i=0;i<3;++i)
  { cout << "isotropic chemical shift (" << i << ") : " << iso_CSA[i] << " Hz\n";
  }
  cout << "# of sampling points:          " << nprop << "\n";
  cout << "# of rotor periods:            " << nrotor << "\n";
  cout << "Powder Quality Number:         " << qu << "  (" << value1[qu] <<
          " orientations)\n";
  cout << "Number of data points:         " << Fnp << " points\n";
  cout << "MAS frequency:                 " << mas_freq << " Hz\n";

	char timex[100];
#ifdef _MSC_VER
	sprintf_s ( timex, "%.6f", time);
#else
	sprintf ( timex, "%.12f", time);
#endif

  cout << "time increments:               " << timex << "s\n";

	char tprop[100];
#ifdef _MSC_VER
	sprintf_s ( tprop, "%.5f", time_prop);
#else
	sprintf ( tprop, "%.10f", time_prop);
#endif

  cout << "dwell time:                    " << tprop << "s\n";
  cout << "jump rate constant             " << kex << " s-1\n";
  cout << "correlation time               " << tauc << " s\n";
  cout << "rf-field amplitude:            " << gamB1 << " Hz\n";
  cout << "Output filename:               " << name << "\n";
  cout << "\n";
  cout.flush();

  ax.Kex(kex,0);
  matrix mx(ax.HS()*ax.HS(), ax.HS()*ax.HS(), i_matrix_type); // ExpLOp is the identity superop
  Iop = super_op(mx);

  block_2D data(nspins,Fnp);
  for(k1=0;k1<nspins;++k1)
  { for(k2=0;k2<Fnp;++k2)
    { data(k1,k2) = 0;
    }
  }

//setup for the hamiltonian
  for(i=0;i<nspins-1;++i)
  { for(j=i+1;j<nspins;++j)
    { Hdip[i][j] = T_D(ax,i,j);
    }
  }

//setup for the space tensor
  matrix help(3,3,0);
  for(i=0;i<2;++i)
  { for(j=i+1;j<3;++j)
    { help.put_h(-1.0/2.0,0,0);
      help.put_h(-1.0/2.0,1,1);
      help.put_h( 1.0,2,2);
      help   = - (complex) D[i][j] * help;
      Adip[i][j] = A2(help);
      Adip[i][j] = Adip[i][j].rotate(alpha_D[i][j],beta_D[i][j],gamma_D[i][j]);
    }
  }

  string name1 = name+".mat";
  string name2 = name;

//here starts the powder loop
//reference JCP 59 (8), 3992 (1973).

  for(count=1; count<=value1[qu]; ++count)
  { beta  = 180.0 * count/value1[qu];
    alpha = 360.0 * ((value2[qu]*count) % value1[qu])/value1[qu];
    gamma = 360.0 * ((value3[qu]*count) % value1[qu])/value1[qu];
    if(count % 10 == 1)
    { //getrusage(0, & me);
      cout << count << "\tbeta = " << beta << "\talpha = "
           << alpha << "\tgamma = " << gamma << "\n";
      cout.flush();
    }
    scale = sin(beta/180.0*PI);
    sigma = iso_CSA[nstart]/sqrt(iso_CSA[nstart]*iso_CSA[nstart]+gamB1*gamB1)*Iz(ax,nstart) +
            gamB1/sqrt(iso_CSA[nstart]*iso_CSA[nstart]+gamB1*gamB1)*Ix(ax,nstart);
    for(k=0;k<nspins;++k)
    { detect[k] = Ix(ax,k);
    }

//now we rotate the space tensor
    for(i=0;i<2;++i)
    { for(j=i+1;j<3;++j)
      { Adip_R[i][j] = Adip[i][j].rotate(alpha,beta,gamma);
      }
    }

//zero all components
    for(i=0;i<5;++i)
      H[i] = gen_op();

//this is the dipolar part
    for(i=0;i<nspins;++i)
      H[2] += iso_CSA[i]*Iz(ax,i);
    for(i=0;i<2;++i)
    { for(j=i+1;j<3;++j)
      { for(k=-2;k<=2;++k)
        { H[k+2] += Adip_R[i][j].component(2,k) * d2(k,0,thetam) * Hdip[i][j].component(2,0);
        }
      }
    }
    for(i=0;i<nprop;++i)
      U[i] = Iop;

//now we calculate the propagator over one cycle of the MAS
    for(ltime=0.5*time;ltime<=steps*time;ltime += time)
    { index = int(ltime/time_prop);
      Ham = gamB1*Fx(ax,"1H");
      for(i=-2;i<=2;++i)
        Ham += exp(complex(0,i*2.0*PI*ltime*mas_freq)) * H[i+2];
      L = complex(0,2.0*PI)*commutator(Ham);
//    cout << "\nHam = \n";
//    cout << Ham;
//    cout << "\nL = \n";
//    cout << L;
      K = Kex(ax, Ham.get_basis());
//    cout << "\nK = \n";
//    cout << K;
//    cout.flush();
      L += K;
      UT = exp(L,-time);
      UT.set_HBR();
      U[index] = UT*U[index];
    }
    for(i=0;i<nprop;++i)
      U[i].set_DBR();
    sigma.set_DBR();
    for(i=0;i<Fnp;++i)
    { for(j=0;j<nspins;++j)
      { data(j,i) += proj(sigma,detect[j])*scale;
      }
      sigma=U[i%nprop]*sigma;
    }
  } // end of powder loop
  MATLAB(name1,name2,data,1);
  exit(0);
}
<commit_msg>Fixed small "oversight" in changing code on windows.<commit_after>/*

sl_exchange5.cc

3 spin simulation with exchange in Hilbert space

*/

#include "gamma.h"
//#include <sys/time.h>
//#include <sys/resource.h>

#define NPROP 1000
#define MAXSPINS 3

using namespace std;

int main(int argc, char *argv[])

{
  sys_dynamic ax;
  gen_op Hrf,Ham, H[5], sigma, sigma1, detect[MAXSPINS];
  super_op Iop,K,L,U[NPROP],UT;
  spin_T  Hdip[MAXSPINS][MAXSPINS];
  space_T Adip[MAXSPINS][MAXSPINS], Adip_R[MAXSPINS][MAXSPINS];
  double D[MAXSPINS][MAXSPINS];
  double iso_CSA[MAXSPINS];
  int i,j,k,k1,k2,Fnp,count,qu,steps,nrotor;
  string name, names;
  const double thetam=54.73561032;
  double mas_freq,gamB1;
  double ltime, time, time_prop, scale;
  int nstart, nspins, index, nprop;
  double alpha,beta,gamma;
  double alpha_D[MAXSPINS][MAXSPINS],beta_D[MAXSPINS][MAXSPINS];
  double gamma_D[MAXSPINS][MAXSPINS];
  double tauc, kex;
  //struct rusage me;
  //struct timeval tp;

  int value1[] = {1, 50, 100, 144, 200, 300, 538, 1154};
  int value2[] = {1,  7,  27,  11,  29,  37,  55,  107};
  int value3[] = {1, 11,  41,  53,  79,  61, 229,  271};

/*initialize the random number generator*/
  //gettimeofday(&tp,NULL);
  //srand48(tp.tv_usec);
  enable_blockdiag();

  count = 1;
  query_parameter(argc,argv,count++,"Spin System Name            ? ", names);
//setup for the spin system
  ax.read(names);
  nspins = ax.spins();
  if(nspins != 3)
  { cerr << "This program is written for a MAXSPINS spin system.\n";
    cerr << "Please change your spin system definition in \n";
    cerr << "the file " << names << ".\n";
    cerr << "Aborting ....\n\n";
    exit(-1);
  }
  for(i=0;i<2;++i)
  { for(j=i+1;j<3;++j)
    { query_parameter(argc,argv,count++,"Dipolar Coupling Constant   ? ", D[i][j]);
      query_parameter(argc,argv,count++,"Euler angle alpha           ? ", alpha_D[i][j]);
      query_parameter(argc,argv,count++,"Euler angle beta            ? ", beta_D[i][j]);
      query_parameter(argc,argv,count++,"Euler angle gamma           ? ", gamma_D[i][j]);
    }
  }
  for(i=0;i<3;++i)
  { query_parameter(argc,argv,count++,"Isotropic chemical shift    ? ", iso_CSA[i]);
  }
  query_parameter(argc,argv,count++,"Powder Quality (cheng)      ? ", qu);
  query_parameter(argc,argv,count++,"Number of time steps        ? ", steps);
  query_parameter(argc,argv,count++,"spinning speed              ? ", mas_freq);
  query_parameter(argc,argv,count++,"Number of rotor periods     ? ", nrotor);
  query_parameter(argc,argv,count++,"Number of sampling per rotor? ", nprop);
  query_parameter(argc,argv,count++,"Initial density operator    ? ", nstart);
  query_parameter(argc,argv,count++,"jump correlation time       ? ", tauc);
  query_parameter(argc,argv,count++,"rf-field amplitude          ? ", gamB1);
  query_parameter(argc,argv,count++,"Output Filename             ? ", name);

  if(nstart >= nspins)
  { cerr << "The starting density operator has a spin number which is\n";
    cerr << "larger than the number of spins.\n";
    cerr << "Aborting ....\n\n";
    exit(-1);
  }

  Fnp = nprop*nrotor;

  time_prop  = (1.0/mas_freq)/nprop;
  time       = (1.0/mas_freq)/steps;
  kex        =1.0/(2.0*tauc);

  cout << "\n\nSimulation of isotropic chemical shift by dipolar coupling\n";
  cout << "==========================================================\n\n";
  cout << "Parameters:\n";
  cout << "rotation angle thetam          : " << thetam << " Degree\n";
  cout << "size of spin system            : " << nspins << " spins\n";
  cout << "initial density operator       : Ix(ax," << nstart << ")\n";
  for(i=0;i<2;++i)
  { for(j=i+1;j<3;++j)
    { cout << "dipolar coupling constant (" << i << "," << j << ") : " <<
              D[i][j] << " Hz\n";
      cout << "relativ orientation of D tensor: (" << alpha_D[i][j] << "," <<
               beta_D[i][j] << "," << gamma_D[i][j] << ")\n";
    }
  }
  for(i=0;i<3;++i)
  { cout << "isotropic chemical shift (" << i << ") : " << iso_CSA[i] << " Hz\n";
  }
  cout << "# of sampling points:          " << nprop << "\n";
  cout << "# of rotor periods:            " << nrotor << "\n";
  cout << "Powder Quality Number:         " << qu << "  (" << value1[qu] <<
          " orientations)\n";
  cout << "Number of data points:         " << Fnp << " points\n";
  cout << "MAS frequency:                 " << mas_freq << " Hz\n";

	char timex[100];
#ifdef _MSC_VER
	sprintf_s ( timex, "%.6f", time);
#else
	sprintf ( timex, "%.6f", time);
#endif

  cout << "time increments:               " << timex << "s\n";

	char tprop[100];
#ifdef _MSC_VER
	sprintf_s ( tprop, "%.5f", time_prop);
#else
	sprintf ( tprop, "%.5f", time_prop);
#endif

  cout << "dwell time:                    " << tprop << "s\n";
  cout << "jump rate constant             " << kex << " s-1\n";
  cout << "correlation time               " << tauc << " s\n";
  cout << "rf-field amplitude:            " << gamB1 << " Hz\n";
  cout << "Output filename:               " << name << "\n";
  cout << "\n";
  cout.flush();

  ax.Kex(kex,0);
  matrix mx(ax.HS()*ax.HS(), ax.HS()*ax.HS(), i_matrix_type); // ExpLOp is the identity superop
  Iop = super_op(mx);

  block_2D data(nspins,Fnp);
  for(k1=0;k1<nspins;++k1)
  { for(k2=0;k2<Fnp;++k2)
    { data(k1,k2) = 0;
    }
  }

//setup for the hamiltonian
  for(i=0;i<nspins-1;++i)
  { for(j=i+1;j<nspins;++j)
    { Hdip[i][j] = T_D(ax,i,j);
    }
  }

//setup for the space tensor
  matrix help(3,3,0);
  for(i=0;i<2;++i)
  { for(j=i+1;j<3;++j)
    { help.put_h(-1.0/2.0,0,0);
      help.put_h(-1.0/2.0,1,1);
      help.put_h( 1.0,2,2);
      help   = - (complex) D[i][j] * help;
      Adip[i][j] = A2(help);
      Adip[i][j] = Adip[i][j].rotate(alpha_D[i][j],beta_D[i][j],gamma_D[i][j]);
    }
  }

  string name1 = name+".mat";
  string name2 = name;

//here starts the powder loop
//reference JCP 59 (8), 3992 (1973).

  for(count=1; count<=value1[qu]; ++count)
  { beta  = 180.0 * count/value1[qu];
    alpha = 360.0 * ((value2[qu]*count) % value1[qu])/value1[qu];
    gamma = 360.0 * ((value3[qu]*count) % value1[qu])/value1[qu];
    if(count % 10 == 1)
    { //getrusage(0, & me);
      cout << count << "\tbeta = " << beta << "\talpha = "
           << alpha << "\tgamma = " << gamma << "\n";
      cout.flush();
    }
    scale = sin(beta/180.0*PI);
    sigma = iso_CSA[nstart]/sqrt(iso_CSA[nstart]*iso_CSA[nstart]+gamB1*gamB1)*Iz(ax,nstart) +
            gamB1/sqrt(iso_CSA[nstart]*iso_CSA[nstart]+gamB1*gamB1)*Ix(ax,nstart);
    for(k=0;k<nspins;++k)
    { detect[k] = Ix(ax,k);
    }

//now we rotate the space tensor
    for(i=0;i<2;++i)
    { for(j=i+1;j<3;++j)
      { Adip_R[i][j] = Adip[i][j].rotate(alpha,beta,gamma);
      }
    }

//zero all components
    for(i=0;i<5;++i)
      H[i] = gen_op();

//this is the dipolar part
    for(i=0;i<nspins;++i)
      H[2] += iso_CSA[i]*Iz(ax,i);
    for(i=0;i<2;++i)
    { for(j=i+1;j<3;++j)
      { for(k=-2;k<=2;++k)
        { H[k+2] += Adip_R[i][j].component(2,k) * d2(k,0,thetam) * Hdip[i][j].component(2,0);
        }
      }
    }
    for(i=0;i<nprop;++i)
      U[i] = Iop;

//now we calculate the propagator over one cycle of the MAS
    for(ltime=0.5*time;ltime<=steps*time;ltime += time)
    { index = int(ltime/time_prop);
      Ham = gamB1*Fx(ax,"1H");
      for(i=-2;i<=2;++i)
        Ham += exp(complex(0,i*2.0*PI*ltime*mas_freq)) * H[i+2];
      L = complex(0,2.0*PI)*commutator(Ham);
//    cout << "\nHam = \n";
//    cout << Ham;
//    cout << "\nL = \n";
//    cout << L;
      K = Kex(ax, Ham.get_basis());
//    cout << "\nK = \n";
//    cout << K;
//    cout.flush();
      L += K;
      UT = exp(L,-time);
      UT.set_HBR();
      U[index] = UT*U[index];
    }
    for(i=0;i<nprop;++i)
      U[i].set_DBR();
    sigma.set_DBR();
    for(i=0;i<Fnp;++i)
    { for(j=0;j<nspins;++j)
      { data(j,i) += proj(sigma,detect[j])*scale;
      }
      sigma=U[i%nprop]*sigma;
    }
  } // end of powder loop
  MATLAB(name1,name2,data,1);
  exit(0);
}
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <af/random_engine.h>

#include <af/array.h>
#include <af/data.h>
#include <af/defines.h>
#include <af/dim4.hpp>
#include <backend.hpp>
#include <err_common.hpp>
#include <handle.hpp>
#include <random_engine.hpp>
#include <MersenneTwister.hpp>

#include <af/util.h>
#include <iostream>

using detail::cfloat;
using detail::cdouble;
using detail::uchar;
using detail::uniformDistribution;
using detail::normalDistribution;

using common::MaxBlocks;
using common::TableLength;
using common::MtStateLength;
using common::pos;
using common::sh1;
using common::sh2;
using common::mask;
using common::recursion_tbl;
using common::temper_tbl;

//TODO : static pointer to random_engine_t that wil hold the default random engine
//protect this object with mutex

//TODO : class and camel case
typedef struct {
    af_random_type type;
    unsigned long long seed;
    unsigned long long counter;
    af_array pos;
    af_array sh1;
    af_array sh2;
    uint mask;
    af_array recursion_table;
    af_array temper_table;
    af_array state;
} af_random_engine_t;

af_random_engine getRandomEngineHandle(const af_random_engine_t engine)
{
    af_random_engine_t *engineHandle = new af_random_engine_t;
    *engineHandle = engine;
    return static_cast<af_random_engine>(engineHandle);
}

af_random_engine_t* getRandomEngine(const af_random_engine engineHandle)
{
    return (af_random_engine_t *)engineHandle;
}

template<typename T>
static inline af_array uniformDistribution_(const af::dim4 &dims, af_random_engine_t *e)
{
    if (e->type == AF_RANDOM_MERSENNE) {
        return getHandle(uniformDistribution<T>(dims,
                    getArray<uint>(e->pos),
                    getArray<uint>(e->sh1),
                    getArray<uint>(e->sh2),
                    e->mask,
                    getArray<uint>(e->recursion_table),
                    getArray<uint>(e->temper_table),
                    getArray<uint>(e->state)));
    } else {
        return getHandle(uniformDistribution<T>(dims, e->type, e->seed, e->counter));
    }
}

template<typename T>
static inline af_array normalDistribution_(const af::dim4 &dims, af_random_engine_t *e)
{
    if (e->type == AF_RANDOM_MERSENNE) {
        return getHandle(normalDistribution<T>(dims,
                    getArray<uint>(e->pos),
                    getArray<uint>(e->sh1),
                    getArray<uint>(e->sh2),
                    e->mask,
                    getArray<uint>(e->recursion_table),
                    getArray<uint>(e->temper_table),
                    getArray<uint>(e->state)));
    } else {
        return getHandle(normalDistribution<T>(dims, e->type, e->seed, e->counter));
    }
}

af_err af_create_random_engine(af_random_engine *engineHandle, af_random_type rtype, unsigned long long seed)
{
    try {
        af_random_engine_t e;
        e.type = rtype;
        e.seed = seed;
        e.counter = 0;
        if (rtype == AF_RANDOM_MERSENNE) {
            //TODO Add AF_CHECK(af_* calls)
            AF_CHECK(af_create_array(&e.pos, pos, 1, &MaxBlocks, u32));
            AF_CHECK(af_create_array(&e.sh1, sh1, 1, &MaxBlocks, u32));
            AF_CHECK(af_create_array(&e.sh2, sh2, 1, &MaxBlocks, u32));
            e.mask = mask;
            AF_CHECK(af_create_array(&e.recursion_table, recursion_tbl, 1, &TableLength, u32));
            AF_CHECK(af_create_array(&e.temper_table, temper_tbl, 1, &TableLength, u32));
            e.state = getHandle(initMersenneState(seed, getArray<uint>(e.recursion_table)));
        }
        *engineHandle = getRandomEngineHandle(e);
    } CATCHALL;

    return AF_SUCCESS;
}

af_err af_random_engine_uniform(af_array *out, af_random_engine engine, const unsigned ndims, const dim_t * const dims, const af_dtype type)
{
    try {
        af_array result;
        AF_CHECK(af_init());

        af::dim4 d = verifyDims(ndims, dims);
        af_random_engine_t *e = getRandomEngine(engine);

        switch(type) {
        case f32:   result = uniformDistribution_<float  >(d, e); break;
        case c32:   result = uniformDistribution_<cfloat >(d, e); break;
        case f64:   result = uniformDistribution_<double >(d, e); break;
        case c64:   result = uniformDistribution_<cdouble>(d, e); break;
        case s32:   result = uniformDistribution_<int    >(d, e); break;
        case u32:   result = uniformDistribution_<uint   >(d, e); break;
        case s64:   result = uniformDistribution_<intl   >(d, e); break;
        case u64:   result = uniformDistribution_<uintl  >(d, e); break;
        case s16:   result = uniformDistribution_<short  >(d, e); break;
        case u16:   result = uniformDistribution_<ushort >(d, e); break;
        case u8:    result = uniformDistribution_<uchar  >(d, e); break;
        case b8:    result = uniformDistribution_<char   >(d, e); break;
        default:    TYPE_ERROR(4, type);
        }
        std::swap(*out, result);
    }
    CATCHALL;
    return AF_SUCCESS;
}

af_err af_random_engine_normal(af_array *out, af_random_engine engine, const unsigned ndims, const dim_t * const dims, const af_dtype type)
{
    try {
        af_array result;
        AF_CHECK(af_init());

        af::dim4 d = verifyDims(ndims, dims);
        af_random_engine_t *e = getRandomEngine(engine);

        switch(type) {
        case f32:   result = normalDistribution_<float  >(d, e); break;
        case c32:   result = normalDistribution_<cfloat >(d, e); break;
        case f64:   result = normalDistribution_<double >(d, e); break;
        case c64:   result = normalDistribution_<cdouble>(d, e); break;
        default:    TYPE_ERROR(4, type);
        }
        std::swap(*out, result);
    }
    CATCHALL;
    return AF_SUCCESS;
}

af_err af_release_random_engine(af_random_engine engineHandle)
{
    try {
        af_random_engine_t *e = getRandomEngine(engineHandle);
        if (e->type == AF_RANDOM_MERSENNE) {
            AF_CHECK(af_release_array(e->pos));
            AF_CHECK(af_release_array(e->sh1));
            AF_CHECK(af_release_array(e->sh2));
            AF_CHECK(af_release_array(e->recursion_table));
            AF_CHECK(af_release_array(e->temper_table));
            AF_CHECK(af_release_array(e->state));
        }
        delete e;
    }
    CATCHALL;
    return AF_SUCCESS;
}
<commit_msg>Changed internal struct to class<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <af/random_engine.h>

#include <af/array.h>
#include <af/data.h>
#include <af/defines.h>
#include <af/dim4.hpp>
#include <backend.hpp>
#include <err_common.hpp>
#include <handle.hpp>
#include <random_engine.hpp>
#include <MersenneTwister.hpp>

#include <af/util.h>
#include <iostream>

using detail::cfloat;
using detail::cdouble;
using detail::uchar;
using detail::uniformDistribution;
using detail::normalDistribution;

using common::MaxBlocks;
using common::TableLength;
using common::MtStateLength;
using common::pos;
using common::sh1;
using common::sh2;
using common::mask;
using common::recursion_tbl;
using common::temper_tbl;

//TODO : static pointer to random_engine_t that wil hold the default random engine
//protect this object with mutex

//TODO : class and camel case
typedef struct {
    af_random_type type;
    unsigned long long seed;
    unsigned long long counter;
    af_array pos;
    af_array sh1;
    af_array sh2;
    uint mask;
    af_array recursion_table;
    af_array temper_table;
    af_array state;
} af_random_engine_t;

class RandomEngine
{
    public :
    af_random_type type;
    unsigned long long seed;
    unsigned long long counter;
    af_array pos;
    af_array sh1;
    af_array sh2;
    uint mask;
    af_array recursion_table;
    af_array temper_table;
    af_array state;
};

af_random_engine getRandomEngineHandle(const RandomEngine engine)
{
    RandomEngine *engineHandle = new RandomEngine;
    *engineHandle = engine;
    return static_cast<af_random_engine>(engineHandle);
}

RandomEngine* getRandomEngine(const af_random_engine engineHandle)
{
    return (RandomEngine *)engineHandle;
}

template<typename T>
static inline af_array uniformDistribution_(const af::dim4 &dims, RandomEngine *e)
{
    if (e->type == AF_RANDOM_MERSENNE) {
        return getHandle(uniformDistribution<T>(dims,
                    getArray<uint>(e->pos),
                    getArray<uint>(e->sh1),
                    getArray<uint>(e->sh2),
                    e->mask,
                    getArray<uint>(e->recursion_table),
                    getArray<uint>(e->temper_table),
                    getArray<uint>(e->state)));
    } else {
        return getHandle(uniformDistribution<T>(dims, e->type, e->seed, e->counter));
    }
}

template<typename T>
static inline af_array normalDistribution_(const af::dim4 &dims, RandomEngine *e)
{
    if (e->type == AF_RANDOM_MERSENNE) {
        return getHandle(normalDistribution<T>(dims,
                    getArray<uint>(e->pos),
                    getArray<uint>(e->sh1),
                    getArray<uint>(e->sh2),
                    e->mask,
                    getArray<uint>(e->recursion_table),
                    getArray<uint>(e->temper_table),
                    getArray<uint>(e->state)));
    } else {
        return getHandle(normalDistribution<T>(dims, e->type, e->seed, e->counter));
    }
}

af_err af_create_random_engine(af_random_engine *engineHandle, af_random_type rtype, unsigned long long seed)
{
    try {
        RandomEngine e;
        e.type = rtype;
        e.seed = seed;
        e.counter = 0;
        if (rtype == AF_RANDOM_MERSENNE) {
            //TODO Add AF_CHECK(af_* calls)
            AF_CHECK(af_create_array(&e.pos, pos, 1, &MaxBlocks, u32));
            AF_CHECK(af_create_array(&e.sh1, sh1, 1, &MaxBlocks, u32));
            AF_CHECK(af_create_array(&e.sh2, sh2, 1, &MaxBlocks, u32));
            e.mask = mask;
            AF_CHECK(af_create_array(&e.recursion_table, recursion_tbl, 1, &TableLength, u32));
            AF_CHECK(af_create_array(&e.temper_table, temper_tbl, 1, &TableLength, u32));
            e.state = getHandle(initMersenneState(seed, getArray<uint>(e.recursion_table)));
        }
        *engineHandle = getRandomEngineHandle(e);
    } CATCHALL;

    return AF_SUCCESS;
}

af_err af_random_engine_uniform(af_array *out, af_random_engine engine, const unsigned ndims, const dim_t * const dims, const af_dtype type)
{
    try {
        af_array result;
        AF_CHECK(af_init());

        af::dim4 d = verifyDims(ndims, dims);
        RandomEngine *e = getRandomEngine(engine);

        switch(type) {
        case f32:   result = uniformDistribution_<float  >(d, e); break;
        case c32:   result = uniformDistribution_<cfloat >(d, e); break;
        case f64:   result = uniformDistribution_<double >(d, e); break;
        case c64:   result = uniformDistribution_<cdouble>(d, e); break;
        case s32:   result = uniformDistribution_<int    >(d, e); break;
        case u32:   result = uniformDistribution_<uint   >(d, e); break;
        case s64:   result = uniformDistribution_<intl   >(d, e); break;
        case u64:   result = uniformDistribution_<uintl  >(d, e); break;
        case s16:   result = uniformDistribution_<short  >(d, e); break;
        case u16:   result = uniformDistribution_<ushort >(d, e); break;
        case u8:    result = uniformDistribution_<uchar  >(d, e); break;
        case b8:    result = uniformDistribution_<char   >(d, e); break;
        default:    TYPE_ERROR(4, type);
        }
        std::swap(*out, result);
    }
    CATCHALL;
    return AF_SUCCESS;
}

af_err af_random_engine_normal(af_array *out, af_random_engine engine, const unsigned ndims, const dim_t * const dims, const af_dtype type)
{
    try {
        af_array result;
        AF_CHECK(af_init());

        af::dim4 d = verifyDims(ndims, dims);
        RandomEngine *e = getRandomEngine(engine);

        switch(type) {
        case f32:   result = normalDistribution_<float  >(d, e); break;
        case c32:   result = normalDistribution_<cfloat >(d, e); break;
        case f64:   result = normalDistribution_<double >(d, e); break;
        case c64:   result = normalDistribution_<cdouble>(d, e); break;
        default:    TYPE_ERROR(4, type);
        }
        std::swap(*out, result);
    }
    CATCHALL;
    return AF_SUCCESS;
}

af_err af_release_random_engine(af_random_engine engineHandle)
{
    try {
        RandomEngine *e = getRandomEngine(engineHandle);
        if (e->type == AF_RANDOM_MERSENNE) {
            AF_CHECK(af_release_array(e->pos));
            AF_CHECK(af_release_array(e->sh1));
            AF_CHECK(af_release_array(e->sh2));
            AF_CHECK(af_release_array(e->recursion_table));
            AF_CHECK(af_release_array(e->temper_table));
            AF_CHECK(af_release_array(e->state));
        }
        delete e;
    }
    CATCHALL;
    return AF_SUCCESS;
}
<|endoftext|>