diff --git a/Sources/examples/CommandLineError.swift b/Sources/examples/CommandLineError.swift index 5e89b82..9851b0e 100644 --- a/Sources/examples/CommandLineError.swift +++ b/Sources/examples/CommandLineError.swift @@ -20,21 +20,21 @@ import Foundation */ public enum CommandLineError: LocalizedError, CustomStringConvertible { - case missingToken - case invalidArgument(argument: String) + case missingOption case invalidOption(option: String) + case invalidInput(input: String) public var errorDescription: String? { return self.description } public var description: String { switch self { - case .missingToken: - return "Missing IBM Quantum Experience token." - case .invalidArgument(let argument): - return "Invalid argument \(argument)." + case .missingOption: + return "Missing option." case .invalidOption(let option): return "Invalid option \(option)." + case .invalidInput(let input): + return "Invalid input \(input)." } } } diff --git a/Sources/examples/CommandLineHandler.swift b/Sources/examples/CommandLineHandler.swift index a32969b..f501e54 100644 --- a/Sources/examples/CommandLineHandler.swift +++ b/Sources/examples/CommandLineHandler.swift @@ -27,6 +27,7 @@ public final class CommandLineHandler { print("Options:") print("--help Shows usage") print("--token Specifies IBM Quantum Experience Token") + print("--local Run examples on local simulator") print("Input:") print("None Runs all examples") print("ghz|qft|rippleadd|teleport Runs specified example") @@ -35,56 +36,67 @@ public final class CommandLineHandler { public func run() throws { guard arguments.count > 1 else { CommandLineHandler.printUsage() - throw CommandLineError.missingToken + throw CommandLineError.missingOption } - // The first argument is the execution path + + var token: String? + var input = "all" + let argument = arguments[1].lowercased() - if argument == "--help" { + switch argument { + case "--help": CommandLineHandler.printUsage() return - } - guard argument == "--token" else { - CommandLineHandler.printUsage() - throw CommandLineError.invalidArgument(argument: argument) - } - guard arguments.count > 2 else { + case "--local": + if arguments.count > 2 { + input = arguments[2].lowercased() + } + case "--token": + guard arguments.count > 2 else { + CommandLineHandler.printUsage() + throw CommandLineError.missingOption + } + token = arguments[2] + + if arguments.count > 3 { + input = arguments[3].lowercased() + } + default: CommandLineHandler.printUsage() - throw CommandLineError.missingToken - } - let token = arguments[2] - var option: String = "all" - if arguments.count > 3 { - option = arguments[3].lowercased() + throw CommandLineError.invalidOption(option: argument) } - switch option { + + let option = CommandLineOption(apiToken: token) + + switch input { case "ghz": - GHZ.ghz(token) { + GHZ.ghz(option) { print("*** Finished ***") exit(0) } case "qft": - QFT.qft(token) { + QFT.qft(option) { print("*** Finished ***") exit(0) } case "rippleadd": - RippleAdd.rippleAdd(token) { + RippleAdd.rippleAdd(option) { print("*** Finished ***") exit(0) } case "teleport": - Teleport.teleport(token) { + Teleport.teleport(option) { print("*** Finished ***") exit(0) } case "all": - GHZ.ghz(token) { + GHZ.ghz(option) { print("*** Finished ***") - QFT.qft(token) { + QFT.qft(option) { print("*** Finished ***") - RippleAdd.rippleAdd(token) { + RippleAdd.rippleAdd(option) { print("*** Finished ***") - Teleport.teleport(token) { + Teleport.teleport(option) { print("*** Finished ***") exit(0) } @@ -93,7 +105,7 @@ public final class CommandLineHandler { } default: CommandLineHandler.printUsage() - throw CommandLineError.invalidOption(option: option) + throw CommandLineError.invalidInput(input: input) } RunLoop.main.run() } diff --git a/Sources/examples/CommandLineOption.swift b/Sources/examples/CommandLineOption.swift new file mode 100644 index 0000000..fc93e0a --- /dev/null +++ b/Sources/examples/CommandLineOption.swift @@ -0,0 +1,30 @@ +// Copyright 2018 IBM RESEARCH. 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. +// ============================================================================= + +import Foundation + +/** + Command Line Option + */ +public struct CommandLineOption { + + enum Backend: String { + case ibmqx2 = "ibmqx2" + case ibmqxQasmSimulator = "ibmqx_qasm_simulator" + case localQasmSimulator = "local_qasm_simulator" + } + + let apiToken: String? +} diff --git a/Sources/examples/ghz.swift b/Sources/examples/ghz.swift index 0ac5854..d33183a 100644 --- a/Sources/examples/ghz.swift +++ b/Sources/examples/ghz.swift @@ -21,7 +21,6 @@ import qiskit */ public final class GHZ { - private static let backend: String = "ibmqx2" private static let QPS_SPECS: [String: Any] = [ "name": "ghz", "circuits": [[ @@ -49,9 +48,154 @@ public final class GHZ { //############################################################## // Make a quantum program for the GHZ state. //############################################################## - @discardableResult - public class func ghz(_ apiToken: String, _ responseHandler: (() -> Void)? = nil) -> RequestTask { + private class func executeRemote(quantumProgram: QuantumProgram, + circuit: String, + _ responseHandler: (() -> Void)?) -> RequestTask { + var reqTask = RequestTask() + + var backend = CommandLineOption.Backend.ibmqxQasmSimulator + print("First version: not compiled") + print("no mapping, simulator") + let r = quantumProgram.execute([circuit], backend: backend.rawValue, coupling_map: nil,shots: 1024) { (result) in + do { + if let error = result.get_error() { + print(error) + responseHandler?() + + return + } + + print(result) + print(try result.get_counts(circuit)) + + print("Second version: map to qx2 coupling graph and simulate") + print("map to \(backend), simulator") + let r = quantumProgram.execute([circuit], backend: backend.rawValue, coupling_map: coupling_map, shots: 1024) { (result) in + do { + if let error = result.get_error() { + print(error) + responseHandler?() + + return + } + + print(result) + print(try result.get_counts(circuit)) + + backend = CommandLineOption.Backend.localQasmSimulator + print("Third version: map to qx2 coupling graph and simulate locally") + print("map to \(backend), local qasm simulator") + let r = quantumProgram.execute([circuit], backend: backend.rawValue, coupling_map: coupling_map, shots: 1024) { (result) in + do { + if let error = result.get_error() { + print(error) + responseHandler?() + + return + } + + print(result) + print(try result.get_counts(circuit)) + + backend = CommandLineOption.Backend.ibmqx2 + print("Fourth version: map to qx2 coupling graph and run on qx2") + print("map to \(backend), backend") + let r = quantumProgram.get_backend_status(backend.rawValue) { (status, e) in + if let error = e { + print(error) + responseHandler?() + + return + } + + print("Status \(backend): \(status)") + guard let available = status["available"] as? Bool else { + print("backend \(backend) not available") + responseHandler?() + + return + } + if !available { + print("backend \(backend) not available") + responseHandler?() + + return + } + let r = quantumProgram.execute([circuit], backend: backend.rawValue, timeout: 120, coupling_map: coupling_map, shots: 1024) { (result) in + do { + if let error = result.get_error() { + print(error) + responseHandler?() + + return + } + + print(result) + print(try result.get_counts(circuit)) + print("ghz end") + } catch { + print(error.localizedDescription) + } + + responseHandler?() + } + reqTask += r + } + reqTask += r + } catch { + print(error.localizedDescription) + responseHandler?() + } + } + reqTask += r + } catch { + print(error.localizedDescription) + responseHandler?() + } + } + reqTask += r + } catch { + print(error.localizedDescription) + responseHandler?() + } + } + reqTask += r + + return reqTask + } + + private class func executeLocal(quantumProgram: QuantumProgram, + circuit: String, + _ responseHandler: (() -> Void)?) -> RequestTask { var reqTask = RequestTask() + + let backend = CommandLineOption.Backend.localQasmSimulator + print("map to qx2 coupling graph and simulate locally") + print("map to \(backend), local qasm simulator") + let r = quantumProgram.execute([circuit], backend: backend.rawValue, coupling_map: coupling_map, shots: 1024) { (result) in + do { + if let error = result.get_error() { + print(error) + responseHandler?() + + return + } + + print(result) + print(try result.get_counts(circuit)) + } catch { + print(error.localizedDescription) + } + + responseHandler?() + } + reqTask += r + + return reqTask + } + + @discardableResult + public class func ghz(_ option: CommandLineOption, _ responseHandler: (() -> Void)? = nil) -> RequestTask { do { print() print("#################################################################") @@ -73,106 +217,22 @@ public final class GHZ { try qc.measure(q[i], c[i]) } - //############################################################## - // Set up the API and execute the program. - //############################################################## - qp.set_api(token: apiToken) - - print("First version: not compiled") - print("no mapping, simulator") - let r = qp.execute(["ghz"], backend: "ibmqx_qasm_simulator", coupling_map: nil,shots: 1024) { (result) in - do { - if let error = result.get_error() { - print(error) - responseHandler?() - return - } - print(result) - print(try result.get_counts("ghz")) - - print("Second version: map to qx2 coupling graph and simulate") - print("map to \(backend), simulator") - let r = qp.execute(["ghz"], backend: "ibmqx_qasm_simulator", coupling_map: coupling_map,shots: 1024) { (result) in - do { - if let error = result.get_error() { - print(error) - responseHandler?() - return - } - print(result) - print(try result.get_counts("ghz")) - - print("Third version: map to qx2 coupling graph and simulate locally") - print("map to \(backend), local qasm simulator") - let r = qp.execute(["ghz"], backend: "local_qasm_simulator",coupling_map: coupling_map,shots: 1024) { (result) in - do { - if let error = result.get_error() { - print(error) - responseHandler?() - return - } - print(result) - print(try result.get_counts("ghz")) - - print("Fourth version: map to qx2 coupling graph and run on qx2") - print("map to \(backend), backend") - let r = qp.get_backend_status(backend) { (status,e) in - if let error = e { - print(error) - responseHandler?() - return - } - print("Status \(backend): \(status)") - guard let available = status["available"] as? Bool else { - print("backend \(backend) not available") - responseHandler?() - return - } - if !available { - print("backend \(backend) not available") - responseHandler?() - return - } - let r = qp.execute(["ghz"], backend: backend,timeout:120, coupling_map: coupling_map,shots: 1024) { (result) in - do { - if let error = result.get_error() { - print(error) - responseHandler?() - return - } - print(result) - print(try result.get_counts("ghz")) - print("ghz end") - } catch { - print(error.localizedDescription) - } - responseHandler?() - } - reqTask += r - } - reqTask += r - } catch { - print(error.localizedDescription) - responseHandler?() - } - } - reqTask += r - } catch { - print(error.localizedDescription) - responseHandler?() - } - } - reqTask += r - } catch { - print(error.localizedDescription) - responseHandler?() - } + if let token = option.apiToken { + //############################################################## + // Set up the API and execute the program. + //############################################################## + qp.set_api(token: token) + + return executeRemote(quantumProgram: qp, circuit: "ghz", responseHandler) } - reqTask += r + + return executeLocal(quantumProgram: qp, circuit: "ghz", responseHandler) } catch { print(error.localizedDescription) + responseHandler?() } - return reqTask + + return RequestTask() } } diff --git a/Sources/examples/qft.swift b/Sources/examples/qft.swift index 4d1cee2..f8ad4a4 100644 --- a/Sources/examples/qft.swift +++ b/Sources/examples/qft.swift @@ -21,8 +21,6 @@ import qiskit */ public final class QFT { - private static let backend: String = "ibmqx2" - private static let QPS_SPECS: [String: Any] = [ "name": "ghz", "circuits": [ @@ -94,9 +92,121 @@ public final class QFT { try circ.h(q[j]) } } - @discardableResult - public class func qft(_ apiToken: String, _ responseHandler: (() -> Void)? = nil) -> RequestTask { + + private class func executeRemote(quantumProgram: QuantumProgram, + circuits: [String], + threeQBitCircuit: String, + _ responseHandler: (() -> Void)?) -> RequestTask { + var reqTask = RequestTask() + + var backend = CommandLineOption.Backend.ibmqxQasmSimulator + let r = quantumProgram.execute(circuits, backend: backend.rawValue, coupling_map: coupling_map, shots: 1024) { (result) in + do { + if let error = result.get_error() { + print(error) + responseHandler?() + + return + } + + print(result) + for name in circuits { + print(try result.get_ran_qasm(name)) + } + for name in circuits { + print(try result.get_counts(name)) + } + + backend = CommandLineOption.Backend.ibmqx2 + let r = quantumProgram.get_backend_status(backend.rawValue) { (status, e) in + if let error = e { + print(error) + responseHandler?() + + return + } + + print("Status \(backend): \(status)") + guard let available = status["available"] as? Bool else { + print("backend \(backend) not available") + responseHandler?() + + return + } + + if !available { + print("backend \(backend) not available") + responseHandler?() + + return + } + + let r = quantumProgram.execute([threeQBitCircuit], backend: backend.rawValue, timeout: 120, coupling_map: coupling_map, shots: 1024) { (result) in + do { + if let error = result.get_error() { + print(error) + responseHandler?() + + return + } + + print(result) + print(try result.get_ran_qasm(threeQBitCircuit)) + print(try result.get_counts(threeQBitCircuit)) + } catch { + print(error.localizedDescription) + } + + responseHandler?() + } + reqTask += r + } + reqTask += r + } catch { + print(error.localizedDescription) + responseHandler?() + } + } + reqTask += r + + return reqTask + } + + private class func executeLocal(quantumProgram: QuantumProgram, + circuits: [String], + _ responseHandler: (() -> Void)?) -> RequestTask { var reqTask = RequestTask() + + let backend = CommandLineOption.Backend.localQasmSimulator + let r = quantumProgram.execute(circuits, backend: backend.rawValue, coupling_map: coupling_map, shots: 1024) { (result) in + do { + if let error = result.get_error() { + print(error) + responseHandler?() + + return + } + + print(result) + for name in circuits { + print(try result.get_ran_qasm(name)) + } + for name in circuits { + print(try result.get_counts(name)) + } + } catch { + print(error.localizedDescription) + } + + responseHandler?() + } + reqTask += r + + return reqTask + } + + @discardableResult + public class func qft(_ option: CommandLineOption, _ responseHandler: (() -> Void)? = nil) -> RequestTask { do { print() print("#################################################################") @@ -137,72 +247,23 @@ public final class QFT { print(qft4.qasm()) print(qft5.qasm()) + let circuits = ["qft3", "qft4", "qft5"] + if let token = option.apiToken { + //############################################################## + // Set up the API and execute the program. + //############################################################## + qp.set_api(token: token) - //############################################################## - // Set up the API and execute the program. - //############################################################## - qp.set_api(token: apiToken) - - let r = qp.execute(["qft3", "qft4", "qft5"], backend:"ibmqx_qasm_simulator", coupling_map: coupling_map,shots: 1024) { (result) in - do { - if let error = result.get_error() { - print(error) - responseHandler?() - return - } - print(result) - print(try result.get_ran_qasm("qft3")) - print(try result.get_ran_qasm("qft4")) - print(try result.get_ran_qasm("qft5")) - print(try result.get_counts("qft3")) - print(try result.get_counts("qft4")) - print(try result.get_counts("qft5")) - - let r = qp.get_backend_status(backend) { (status,e) in - if let error = e { - print(error) - responseHandler?() - return - } - print("Status \(backend): \(status)") - guard let available = status["available"] as? Bool else { - print("backend \(backend) not available") - responseHandler?() - return - } - if !available { - print("backend \(backend) not available") - responseHandler?() - return - } - let r = qp.execute(["qft3"], backend:backend,timeout:120, coupling_map: coupling_map,shots: 1024) { (result) in - do { - if let error = result.get_error() { - print(error) - responseHandler?() - return - } - print(result) - print(try result.get_ran_qasm("qft3")) - print(try result.get_counts("qft3")) - } catch { - print(error.localizedDescription) - } - responseHandler?() - } - reqTask += r - } - reqTask += r - } catch { - print(error.localizedDescription) - responseHandler?() - } + return executeRemote(quantumProgram: qp, circuits: circuits, threeQBitCircuit: "qft3", responseHandler) } - reqTask += r + + return executeLocal(quantumProgram: qp, circuits: circuits, responseHandler) } catch { print(error.localizedDescription) + responseHandler?() } - return reqTask + + return RequestTask() } } diff --git a/Sources/examples/rippleadd.swift b/Sources/examples/rippleadd.swift index 5f3d4ad..1fba713 100644 --- a/Sources/examples/rippleadd.swift +++ b/Sources/examples/rippleadd.swift @@ -18,7 +18,6 @@ import qiskit public final class RippleAdd { - private static let backend: String = "ibmqx_qasm_simulator" private static let coupling_map = [0: [1, 8], 1: [2, 9], 2: [3, 10], 3: [4, 11], 4: [5, 12], 5: [6, 13], 6: [7, 14], 7: [15], 8: [9], 9: [10], 10: [11], 11: [12], 12: [13], 13: [14], 14: [15] @@ -43,8 +42,9 @@ public final class RippleAdd { private init() { } + @discardableResult - public class func rippleAdd(_ apiToken: String, _ responseHandler: (() -> Void)? = nil) -> RequestTask { + public class func rippleAdd(_ option: CommandLineOption, _ responseHandler: (() -> Void)? = nil) -> RequestTask { var reqTask = RequestTask() do { print() @@ -85,26 +85,33 @@ public final class RippleAdd { //############################################################### //# Set up the API and execute the program. //############################################################### - qp.set_api(token: apiToken) + var backend = CommandLineOption.Backend.localQasmSimulator + if let token = option.apiToken { + qp.set_api(token: token) + + backend = CommandLineOption.Backend.ibmqxQasmSimulator + } print("First version: not mapped") - let r = qp.execute(["rippleadd"], backend: backend, coupling_map: nil,shots: 1024) { (result) in + let r = qp.execute(["rippleadd"], backend: backend.rawValue, coupling_map: nil, shots: 1024) { (result) in do { if let error = result.get_error() { print(error) responseHandler?() + return } print(result) print(try result.get_counts("rippleadd")) print("Second version: mapped to 2x8 array coupling graph") let r = qp.compile(["rippleadd"], - backend: backend, + backend: backend.rawValue, coupling_map: coupling_map, shots: 1024) { (qobj,error) in if error != nil { print(error!) responseHandler?() + return } let r = qp.run_async(qobj) { (result) in @@ -112,6 +119,7 @@ public final class RippleAdd { if let error = result.get_error() { print(error) responseHandler?() + return } print(result) @@ -121,6 +129,7 @@ public final class RippleAdd { } catch { print(error.localizedDescription) } + responseHandler?() } reqTask += r diff --git a/Sources/examples/teleport.swift b/Sources/examples/teleport.swift index 816bfe0..321a954 100644 --- a/Sources/examples/teleport.swift +++ b/Sources/examples/teleport.swift @@ -21,8 +21,6 @@ import qiskit */ public final class Teleport { - private static let backend: String = "ibmqx_qasm_simulator" - private static let QPS_SPECS: [String: Any] = [ "name": "Program", "circuits": [[ @@ -56,7 +54,7 @@ public final class Teleport { // Make a quantum program for the GHZ and Bell states. //############################################################## @discardableResult - public class func teleport(_ apiToken: String, _ responseHandler: (() -> Void)? = nil) -> RequestTask { + public class func teleport(_ option: CommandLineOption, _ responseHandler: (() -> Void)? = nil) -> RequestTask { var reqTask = RequestTask() do { print() @@ -93,27 +91,34 @@ public final class Teleport { //############################################################## // Set up the API and execute the program. //############################################################## - qp.set_api(token: apiToken) + var backend = CommandLineOption.Backend.localQasmSimulator + if let token = option.apiToken { + qp.set_api(token: token) + + backend = CommandLineOption.Backend.ibmqxQasmSimulator + } print("Experiment does not support feedback, so we use the simulator") print("First version: not mapped") - let r = qp.execute(["teleport"], backend: backend,coupling_map: nil,shots: 1024) { (result) in + let r = qp.execute(["teleport"], backend: backend.rawValue, coupling_map: nil, shots: 1024) { (result) in do { if let error = result.get_error() { print(error) responseHandler?() + return } print(result) print(try result.get_counts("teleport")) print("Second version: mapped to qx2 coupling graph") - let r = qp.execute(["teleport"], backend: backend,coupling_map: coupling_map,shots: 1024) { (result) in + let r = qp.execute(["teleport"], backend: backend.rawValue, coupling_map: coupling_map, shots: 1024) { (result) in do { if let error = result.get_error() { print(error) responseHandler?() + return } print(result) @@ -123,6 +128,7 @@ public final class Teleport { } catch { print(error.localizedDescription) } + responseHandler?() } reqTask += r