XACC
js.hpp
1 /*******************************************************************************
2  * Copyright (c) 2019 UT-Battelle, LLC.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * and Eclipse Distribution License v1.0 which accompanies this
6  * distribution. The Eclipse Public License is available at
7  * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
8  *License is available at https://eclipse.org/org/documents/edl-v10.php
9  *
10  * Contributors:
11  * Alexander J. McCaskey - initial API and implementation
12  *******************************************************************************/
13 #ifndef XACC_ALGORITHM_DDCL_STRATEGIES_JS_LOSS_HPP_
14 #define XACC_ALGORITHM_DDCL_STRATEGIES_JS_LOSS_HPP_
15 
16 #include "ddcl.hpp"
17 #include "xacc.hpp"
18 #include <cassert>
19 #include <set>
20 #include "InstructionIterator.hpp"
21 namespace xacc {
22 namespace algorithm {
23 
24 class JSLossStrategy : public LossStrategy {
25 protected:
26  // Helper function
27  double entropy(const std::vector<double> p, const std::vector<double> q) {
28  double sum = 0.0;
29  for (int i = 0; i < p.size(); i++) {
30  if (std::fabs(p[i]) > 1e-12) {
31  sum += p[i] * std::log(p[i] / q[i]);
32  }
33  }
34  return sum;
35  }
36 
37 public:
38  std::pair<double, std::vector<double>>
39  compute(Counts &counts, const std::vector<double> &target, const HeterogeneousMap& = {}) override {
40  int shots = 0;
41  for (auto &x : counts) {
42  shots += x.second;
43  }
44 
45  // Compute the probability distribution
46  std::vector<double> q(target.size()); // all zeros
47  for (auto &x : counts) {
48  int idx = std::stoi(x.first, nullptr, 2);
49  q[idx] = (double)x.second / shots;
50  }
51 
52  // get M=1/2(P+Q)
53  std::vector<double> m(target.size());
54  for (int i = 0; i < m.size(); i++) {
55  m[i] = .5 * (target[i] + q[i]);
56  }
57 
58  auto js = 0.5 * (entropy(target, m) + entropy(q, m));
59  return std::make_pair(js, q);
60  }
61 
62  bool isValidGradientStrategy(const std::string &gradientStrategy) override {
63  // FIXME define what grad strategies this guy works with
64  return true;
65  }
66  const std::string name() const override { return "js"; }
67  const std::string description() const override { return ""; }
68 };
69 
71 protected:
72  std::vector<double> currentParameterSet;
73 
74 public:
75  std::vector<Circuit>
76  getCircuitExecutions(Circuit circuit, const std::vector<double> &x) override {
77  currentParameterSet = x;
78  std::set<std::size_t> uniqueBits = circuit->uniqueBits();
79  std::vector<Circuit> grad_circuits;
80  auto provider = xacc::getIRProvider("quantum");
81  for (int i = 0; i < x.size(); i++) {
82  auto xplus = x[i] + xacc::constants::pi / 2.;
83  auto xminus = x[i] - xacc::constants::pi / 2.;
84  std::vector<double> tmpx_plus = x, tmpx_minus = x;
85  tmpx_plus[i] = xplus;
86  tmpx_minus[i] = xminus;
87  auto xplus_circuit = circuit->operator()(tmpx_plus);
88  auto xminus_circuit = circuit->operator()(tmpx_minus);
89 
90  xplus_circuit->setName(circuit->name()+"param_"+std::to_string(i)+"_shift_plus");
91  xminus_circuit->setName(circuit->name()+"param_"+std::to_string(i)+"_shift_minus");
92 
93  for (auto &ii : uniqueBits) {
94  auto m = provider->createInstruction("Measure",
95  std::vector<std::size_t>{ii});
96  xplus_circuit->addInstruction(m);
97  }
98  for (auto &ii : uniqueBits) {
99  auto m = provider->createInstruction("Measure",
100  std::vector<std::size_t>{ii});
101  xminus_circuit->addInstruction(m);
102  }
103  grad_circuits.push_back(xplus_circuit);
104  grad_circuits.push_back(xminus_circuit);
105  }
106 
107  return grad_circuits;
108  }
109 
110  void compute(std::vector<double> &grad, std::vector<std::shared_ptr<AcceleratorBuffer>> results,
111  const std::vector<double> &q_dist,
112  const std::vector<double> &target_dist) override {
113  assert(2 * grad.size() == results.size());
114 
115  // Get the number of shosts
116  int shots = 0;
117  for (auto &x : results[0]->getMeasurementCounts()) {
118  shots += x.second;
119  }
120 
121  // Create q+ and q- vectors
122  int counter = 0;
123  std::vector<std::vector<double>> qplus_theta, qminus_theta;
124  for (int i = 0; i < results.size(); i += 2) {
125  std::vector<double> qp(q_dist.size()), qm(q_dist.size());
126  for (auto &x : results[i]->getMeasurementCounts()) {
127  int idx = std::stoi(x.first, nullptr, 2);
128  qp[idx] = (double)x.second / shots;
129  }
130  for (auto &x : results[i + 1]->getMeasurementCounts()) {
131  int idx = std::stoi(x.first, nullptr, 2);
132  qm[idx] = (double)x.second / shots;
133  }
134 
135  std::vector<double> shiftedp = currentParameterSet;
136  std::vector<double> shiftedm = currentParameterSet;
137  auto xplus = currentParameterSet[counter] + xacc::constants::pi / 2.;
138  auto xminus = currentParameterSet[counter] - xacc::constants::pi / 2.;
139 
140  shiftedp[counter] = xplus;
141  shiftedm[counter] = xminus;
142 
143  results[i]->addExtraInfo("gradient-index", counter);
144  results[i+1]->addExtraInfo("gradient-index", counter);
145 
146  results[i]->addExtraInfo("shift-direction", "plus");
147  results[i+1]->addExtraInfo("shift-direction", "minus");
148 
149  results[i]->addExtraInfo("qdist", qp);
150  results[i+1]->addExtraInfo("qdist", qm);
151 
152  results[i]->addExtraInfo("gradient-parameters", shiftedp);
153  results[i+1]->addExtraInfo("gradient-parameters", shiftedm);
154 
155  qplus_theta.push_back(qp);
156  qminus_theta.push_back(qm);
157 
158  counter++;
159  }
160 
161  for (int i = 0; i < grad.size(); i++) {
162  double sum = 0.0;
163  for (int x = 0; x < q_dist.size(); x++) {
164  if (std::fabs(q_dist[x]) > 1e-12) {
165  sum += std::log(q_dist[x] / (0.5 * (target_dist[x] + q_dist[x]))) *
166  0.5 * (qplus_theta[i][x] - qminus_theta[i][x]);
167  }
168  }
169  sum *= 0.5;
170  grad[i] = sum;
171  }
172 
173  return;
174  }
175 
176  const std::string name() const override { return "js-parameter-shift"; }
177  const std::string description() const override { return ""; }
178 };
179 } // namespace algorithm
180 } // namespace xacc
181 #endif
Definition: ddcl.hpp:24
const std::string description() const override
Definition: js.hpp:177
Definition: js.hpp:24
Definition: Accelerator.hpp:25
const std::string name() const override
Definition: js.hpp:66
const std::string name() const override
Definition: js.hpp:176
Definition: heterogeneous.hpp:45
Definition: ddcl.hpp:32
const std::string description() const override
Definition: js.hpp:67