diff --git a/Package.swift b/Package.swift index 87e6de0..56cc212 100644 --- a/Package.swift +++ b/Package.swift @@ -3,6 +3,20 @@ import PackageDescription +var packageDependencies: [Package.Dependency] = [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), +] + +#if os(Linux) + +packageDependencies += [ + .package(url: "https://github.com/indisoluble/CWebkitGtk-Linux.git", from: "1.0.0"), + .package(url: "https://github.com/indisoluble/CLapacke-Linux.git", from: "1.0.0"), +] + +#endif + let package = Package( name: "qiskit", products: [ @@ -13,10 +27,7 @@ let package = Package( .executable( name: "qiskitexamples", targets: ["examples"]), ], - dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), - ], + dependencies: packageDependencies, targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages which this package depends on. diff --git a/Sources/qiskit/datastructures/Matrix.swift b/Sources/qiskit/datastructures/Matrix.swift index 0f870a7..a2cae12 100644 --- a/Sources/qiskit/datastructures/Matrix.swift +++ b/Sources/qiskit/datastructures/Matrix.swift @@ -17,6 +17,10 @@ import Accelerate +#elseif os(Linux) + +import CLapacke_Linux + #endif import Foundation @@ -453,8 +457,6 @@ extension Matrix where T == Complex { return m } - #if os(OSX) || os(iOS) - public func eigh() throws -> (Vector, [Vector]) { guard isHermitian else { throw ArrayError.matrixIsNotHermitian @@ -468,6 +470,9 @@ extension Matrix where T == Complex { var info = Int32() var w = Array(repeating: Double(), count: rowCount) + + #if os(OSX) || os(iOS) + var a = flattenCol().map { __CLPK_doublecomplex(r: $0.real, i: $0.imag) } // Get optimal workspace @@ -490,19 +495,36 @@ extension Matrix where T == Complex { zheevd_(&jobz, &uplo, &n, &a, &lda, &w, &work, &lengthWork, &rWork, &lengthRWork, &iWork, &lengthIWork, &info) + #elseif os(Linux) + + var a = flattenCol().value + let aPointer = UnsafeMutablePointer(mutating: a) + let aOpaquePointer = OpaquePointer(aPointer) + + info = LAPACKE_zheevd(LAPACK_COL_MAJOR, jobz, uplo, n, aOpaquePointer, lda, &w) + + #endif + // Validate results if (info > 0) { throw ArrayError.unableToComputeEigenValues } + #if os(OSX) || os(iOS) + let aComplex = MultiDArray(value: a.map { Complex($0.r, $0.i) }) + + #elseif os(Linux) + + let aComplex = MultiDArray(value: a) + + #endif + let vectorsStoredByCol = try aComplex.reshape([rowCount, rowCount]).value as! [[Complex]] return (Vector(value: w), vectorsStoredByCol.map { Vector(value: $0) }) } - #endif - public func sqrt() -> Matrix { var m = Matrix(repeating: 0, rows: self.rowCount, cols: self.colCount) for row in 0.., @@ -81,7 +79,7 @@ private func plot_state_city(_ rho: Matrix, realValues: realValues, imagValues: imagValues) - return AppleWebViewFactory.makeWebView(size: size, html: html) + return WebViewFactory.makeWebView(size: size, html: html) } private func plot_state_paulivec(_ rho: Matrix, @@ -108,7 +106,7 @@ private func plot_state_paulivec(_ rho: Matrix, values: values, configuration: configuration) - return AppleWebViewFactory.makeWebView(size: size, html: html) + return WebViewFactory.makeWebView(size: size, html: html) } private func pauli_group(_ numberofqubits: Int) -> [Pauli] { @@ -146,7 +144,7 @@ private func plot_state_bloch(_ rho: Matrix, let html = StateBlochChartHtmlFactory.makeHtml(blochStates: bloch_states) - return AppleWebViewFactory.makeWebView(size: size, html: html) + return WebViewFactory.makeWebView(size: size, html: html) } private func plot_state_qsphere(_ rho: Matrix, @@ -176,7 +174,7 @@ private func plot_state_qsphere(_ rho: Matrix, let html = StateQsphereChartHtmlFactory.makeHtml(numberOfBits: numberOfBits, series: series) - return AppleWebViewFactory.makeWebView(size: size, html: html) + return WebViewFactory.makeWebView(size: size, html: html) } private func matrix_eigh(_ rho: Matrix) -> (Vector, [Vector]) { @@ -278,5 +276,3 @@ private func phase_to_color_wheel(_ complex: Complex) -> StateQsphereChartValue. return StateQsphereChartValue.Color(rawValue: angle_round)! } - -#endif diff --git a/Sources/qiskit/tools/visualization/VisualizationTypes.swift b/Sources/qiskit/tools/visualization/VisualizationTypes.swift index d34c01c..56e0a00 100644 --- a/Sources/qiskit/tools/visualization/VisualizationTypes.swift +++ b/Sources/qiskit/tools/visualization/VisualizationTypes.swift @@ -13,16 +13,18 @@ // limitations under the License. // ============================================================================= -#if os(OSX) || os(iOS) - #if os(OSX) import Cocoa -#else +#elseif os(iOS) import UIKit +#elseif os(Linux) + +import CWebkitGtk_Linux + #endif // MARK: - Public body @@ -35,10 +37,14 @@ public struct VisualizationTypes { public typealias View = NSView - #else + #elseif os(iOS) public typealias View = UIView + #elseif os(Linux) + + public typealias View = UnsafeMutablePointer + #endif public struct Size { @@ -56,5 +62,3 @@ public struct VisualizationTypes { } } } - -#endif diff --git a/Sources/qiskit/tools/visualization/charts/BarChartConfiguration.swift b/Sources/qiskit/tools/visualization/charts/BarChartConfiguration.swift index e25a331..4c8a33c 100644 --- a/Sources/qiskit/tools/visualization/charts/BarChartConfiguration.swift +++ b/Sources/qiskit/tools/visualization/charts/BarChartConfiguration.swift @@ -13,8 +13,6 @@ // limitations under the License. // ============================================================================= -#if os(OSX) || os(iOS) - // MARK: - Main body struct BarChartConfiguration { @@ -44,5 +42,3 @@ struct BarChartConfiguration { self.showValueOnTop = showValueOnTop } } - -#endif diff --git a/Sources/qiskit/tools/visualization/charts/BarChartHtmlFactory.swift b/Sources/qiskit/tools/visualization/charts/BarChartHtmlFactory.swift index ece397e..91ca86d 100644 --- a/Sources/qiskit/tools/visualization/charts/BarChartHtmlFactory.swift +++ b/Sources/qiskit/tools/visualization/charts/BarChartHtmlFactory.swift @@ -13,8 +13,6 @@ // limitations under the License. // ============================================================================= -#if os(OSX) || os(iOS) - import Foundation // MARK: - Main body @@ -110,5 +108,3 @@ struct BarChartHtmlFactory { """ } } - -#endif diff --git a/Sources/qiskit/tools/visualization/charts/StateBlochChartHtmlFactory.swift b/Sources/qiskit/tools/visualization/charts/StateBlochChartHtmlFactory.swift index 42f02e6..83eba61 100644 --- a/Sources/qiskit/tools/visualization/charts/StateBlochChartHtmlFactory.swift +++ b/Sources/qiskit/tools/visualization/charts/StateBlochChartHtmlFactory.swift @@ -13,8 +13,6 @@ // limitations under the License. // ============================================================================= -#if os(OSX) || os(iOS) - import Foundation // MARK: - Main body @@ -157,5 +155,3 @@ struct StateBlochChartHtmlFactory { """ } } - -#endif diff --git a/Sources/qiskit/tools/visualization/charts/StateCityChartHtmlFactory.swift b/Sources/qiskit/tools/visualization/charts/StateCityChartHtmlFactory.swift index 122b4c1..33081ac 100644 --- a/Sources/qiskit/tools/visualization/charts/StateCityChartHtmlFactory.swift +++ b/Sources/qiskit/tools/visualization/charts/StateCityChartHtmlFactory.swift @@ -13,8 +13,6 @@ // limitations under the License. // ============================================================================= -#if os(OSX) || os(iOS) - import Foundation // MARK: - Main body @@ -112,5 +110,3 @@ struct StateCityChartHtmlFactory { """ } } - -#endif diff --git a/Sources/qiskit/tools/visualization/charts/StateQsphereChartHtmlFactory.swift b/Sources/qiskit/tools/visualization/charts/StateQsphereChartHtmlFactory.swift index 68e0ddb..95dca92 100644 --- a/Sources/qiskit/tools/visualization/charts/StateQsphereChartHtmlFactory.swift +++ b/Sources/qiskit/tools/visualization/charts/StateQsphereChartHtmlFactory.swift @@ -13,8 +13,6 @@ // limitations under the License. // ============================================================================= -#if os(OSX) || os(iOS) - import Foundation // MARK: - Main body @@ -160,5 +158,3 @@ struct StateQsphereChartHtmlFactory { """ } } - -#endif diff --git a/Sources/qiskit/tools/visualization/charts/StateQsphereChartSerie.swift b/Sources/qiskit/tools/visualization/charts/StateQsphereChartSerie.swift index acfd4c2..ba6f257 100644 --- a/Sources/qiskit/tools/visualization/charts/StateQsphereChartSerie.swift +++ b/Sources/qiskit/tools/visualization/charts/StateQsphereChartSerie.swift @@ -13,8 +13,6 @@ // limitations under the License. // ============================================================================= -#if os(OSX) || os(iOS) - // MARK: - Main body struct StateQsphereChartSerie { @@ -24,5 +22,3 @@ struct StateQsphereChartSerie { let probMix: Double let values: [StateQsphereChartValue] } - -#endif diff --git a/Sources/qiskit/tools/visualization/charts/StateQsphereChartValue.swift b/Sources/qiskit/tools/visualization/charts/StateQsphereChartValue.swift index f34a3b9..889bd2d 100644 --- a/Sources/qiskit/tools/visualization/charts/StateQsphereChartValue.swift +++ b/Sources/qiskit/tools/visualization/charts/StateQsphereChartValue.swift @@ -13,8 +13,6 @@ // limitations under the License. // ============================================================================= -#if os(OSX) || os(iOS) - // MARK: - Main body struct StateQsphereChartValue { @@ -84,5 +82,3 @@ struct StateQsphereChartValue { return rgba } } - -#endif diff --git a/Sources/qiskit/tools/visualization/charts/WebViewFactory.swift b/Sources/qiskit/tools/visualization/charts/WebViewFactory.swift new file mode 100644 index 0000000..cf1d2cb --- /dev/null +++ b/Sources/qiskit/tools/visualization/charts/WebViewFactory.swift @@ -0,0 +1,35 @@ +// 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 + +// MARK: - Main body + +struct WebViewFactory { + + // MARK: - Public class methods + + static func makeWebView(size: VisualizationTypes.Size, html: String) -> VisualizationTypes.View { + #if os(OSX) || os(iOS) + + return AppleWebViewFactory.makeWebView(size: size, html: html) + + #elseif os(Linux) + + return LinuxWebViewFactory.makeWebView(html: html) + + #endif + } +} diff --git a/Sources/qiskit/tools/visualization/charts/platforms/LinuxWebViewFactory.swift b/Sources/qiskit/tools/visualization/charts/platforms/LinuxWebViewFactory.swift new file mode 100644 index 0000000..92598d6 --- /dev/null +++ b/Sources/qiskit/tools/visualization/charts/platforms/LinuxWebViewFactory.swift @@ -0,0 +1,72 @@ +// 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. +// ============================================================================= + +#if os(Linux) + +import CWebkitGtk_Linux + +// MARK: - Main body + +struct LinuxWebViewFactory { + + // MARK: - Public class methods + + static func makeWebView(html: String) -> VisualizationTypes.View { + let widget = webkit_web_view_new()! + enableWebGL(in: widget) + loadHtml(html, in: widget) + + return widget + } +} + +// MARK: - Private body + +private extension LinuxWebViewFactory { + + // MARK: - Constants + + enum Constants { + static let webviewSettingsEnableWebGL = "enable-webgl" + } + + // MARK: - Private class methods + + static func enableWebGL(in widget: VisualizationTypes.View) { + let webview = UnsafeMutablePointer(OpaquePointer(widget)) + let webviewSettings = webkit_web_view_get_settings(webview) + let objectSettings = UnsafeMutablePointer(OpaquePointer(webviewSettings)) + + var value = valueTrue() + g_object_set_property(objectSettings, Constants.webviewSettingsEnableWebGL, &value) + } + + static func valueTrue() -> GValue { + var value = GValue() + let type = GType(5 << G_TYPE_FUNDAMENTAL_SHIFT) // G_TYPE_BOOLEAN + g_value_init(&value, type) + g_value_set_boolean (&value, 1) // TRUE + + return value + } + + static func loadHtml(_ html: String, in widget: VisualizationTypes.View) { + let webview = UnsafeMutablePointer(OpaquePointer(widget)) + + webkit_web_view_load_html_string(webview, html, nil) + } +} + +#endif diff --git a/Tests/qiskitTests/DataStructureTests.swift b/Tests/qiskitTests/DataStructureTests.swift index 530c2bb..d322d16 100644 --- a/Tests/qiskitTests/DataStructureTests.swift +++ b/Tests/qiskitTests/DataStructureTests.swift @@ -259,9 +259,6 @@ class DataStructureTests: XCTestCase { b[1, 0] = Complex(0, -1) XCTAssertFalse(a.isHermitian) XCTAssertTrue(b.isHermitian) - - #if os(OSX) || os(iOS) - XCTAssertThrowsError(try a.eigh()) let (values, vectors) = try! b.eigh() let expectedValues = Vector(value: [1.0, 3.0, 3.0]) @@ -280,8 +277,6 @@ class DataStructureTests: XCTestCase { XCTAssertEqual(oneVector[j].imag, oneExpectedVector[j].imag, accuracy: 0.00001) } } - - #endif } func testTrace() { diff --git a/qiskit.xcodeproj/project.pbxproj b/qiskit.xcodeproj/project.pbxproj index af86164..e5ded7a 100644 --- a/qiskit.xcodeproj/project.pbxproj +++ b/qiskit.xcodeproj/project.pbxproj @@ -365,6 +365,8 @@ FF9A9C42206ED7AE006589F2 /* StateQsphereChartSerie.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9A9C40206ED7AE006589F2 /* StateQsphereChartSerie.swift */; }; FF9A9C44206EF7D0006589F2 /* StateQsphereChartHtmlFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9A9C43206EF7D0006589F2 /* StateQsphereChartHtmlFactory.swift */; }; FF9A9C45206EF7D0006589F2 /* StateQsphereChartHtmlFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9A9C43206EF7D0006589F2 /* StateQsphereChartHtmlFactory.swift */; }; + FFEFC6672053178D0073B544 /* WebViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEFC6662053178D0073B544 /* WebViewFactory.swift */; }; + FFEFC6682053178D0073B544 /* WebViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEFC6662053178D0073B544 /* WebViewFactory.swift */; }; FFEFC66A20533CAF0073B544 /* StateBlochChartHtmlFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEFC66920533CAF0073B544 /* StateBlochChartHtmlFactory.swift */; }; FFEFC66B20533CAF0073B544 /* StateBlochChartHtmlFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEFC66920533CAF0073B544 /* StateBlochChartHtmlFactory.swift */; }; /* End PBXBuildFile section */ @@ -578,6 +580,7 @@ FF98E5FB204B68540026ADEC /* StateCityChartHtmlFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StateCityChartHtmlFactory.swift; path = Sources/qiskit/tools/visualization/charts/StateCityChartHtmlFactory.swift; sourceTree = SOURCE_ROOT; }; FF98E5FC204B68540026ADEC /* BarChartHtmlFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BarChartHtmlFactory.swift; path = Sources/qiskit/tools/visualization/charts/BarChartHtmlFactory.swift; sourceTree = SOURCE_ROOT; }; FF98E608204B68FB0026ADEC /* AppleWebViewFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppleWebViewFactory.swift; path = Sources/qiskit/tools/visualization/charts/platforms/AppleWebViewFactory.swift; sourceTree = SOURCE_ROOT; }; + FF98E609204B68FC0026ADEC /* LinuxWebViewFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinuxWebViewFactory.swift; path = Sources/qiskit/tools/visualization/charts/platforms/LinuxWebViewFactory.swift; sourceTree = SOURCE_ROOT; }; FF98E60F204B6E4A0026ADEC /* echarts.min.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = echarts.min.swift; path = "Sources/qiskit/tools/visualization/resources/echarts-4.0.4/echarts.min.swift"; sourceTree = SOURCE_ROOT; }; FF98E610204B6E4A0026ADEC /* echarts.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = echarts.min.js; path = "Sources/qiskit/tools/visualization/resources/echarts-4.0.4/echarts.min.js"; sourceTree = SOURCE_ROOT; }; FF98E611204B6E4A0026ADEC /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = "Sources/qiskit/tools/visualization/resources/echarts-4.0.4/LICENSE"; sourceTree = SOURCE_ROOT; }; @@ -587,6 +590,7 @@ FF9A9C3D206EC385006589F2 /* StateQsphereChartValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StateQsphereChartValue.swift; path = Sources/qiskit/tools/visualization/charts/StateQsphereChartValue.swift; sourceTree = SOURCE_ROOT; }; FF9A9C40206ED7AE006589F2 /* StateQsphereChartSerie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StateQsphereChartSerie.swift; path = Sources/qiskit/tools/visualization/charts/StateQsphereChartSerie.swift; sourceTree = SOURCE_ROOT; }; FF9A9C43206EF7D0006589F2 /* StateQsphereChartHtmlFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StateQsphereChartHtmlFactory.swift; path = Sources/qiskit/tools/visualization/charts/StateQsphereChartHtmlFactory.swift; sourceTree = SOURCE_ROOT; }; + FFEFC6662053178D0073B544 /* WebViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WebViewFactory.swift; path = Sources/qiskit/tools/visualization/charts/WebViewFactory.swift; sourceTree = SOURCE_ROOT; }; FFEFC66920533CAF0073B544 /* StateBlochChartHtmlFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StateBlochChartHtmlFactory.swift; path = Sources/qiskit/tools/visualization/charts/StateBlochChartHtmlFactory.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -1055,6 +1059,7 @@ FF9A9C43206EF7D0006589F2 /* StateQsphereChartHtmlFactory.swift */, FF9A9C40206ED7AE006589F2 /* StateQsphereChartSerie.swift */, FF9A9C3D206EC385006589F2 /* StateQsphereChartValue.swift */, + FFEFC6662053178D0073B544 /* WebViewFactory.swift */, FF98E607204B68770026ADEC /* platforms */, ); path = charts; @@ -1064,6 +1069,7 @@ isa = PBXGroup; children = ( FF98E608204B68FB0026ADEC /* AppleWebViewFactory.swift */, + FF98E609204B68FC0026ADEC /* LinuxWebViewFactory.swift */, ); path = platforms; sourceTree = ""; @@ -1308,6 +1314,7 @@ 6932AB511FB9F90400382CF7 /* NodeGateBody.swift in Sources */, 6932AAEB1FB9F7D700382CF7 /* Gate.swift in Sources */, 6932AB601FB9F92F00382CF7 /* NodeProgram.swift in Sources */, + FFEFC6682053178D0073B544 /* WebViewFactory.swift in Sources */, 6932AAF31FB9F7EE00382CF7 /* QuantumCircuit.swift in Sources */, FF98E602204B68570026ADEC /* BarChartConfiguration.swift in Sources */, 6932AA851FB9F6B900382CF7 /* CX.swift in Sources */, @@ -1474,6 +1481,7 @@ 6932AB381FB9F8CB00382CF7 /* NodeOpaque.swift in Sources */, 6932AA781FB9F69300382CF7 /* T.swift in Sources */, 6932AA631FB9F69300382CF7 /* Header.swift in Sources */, + FFEFC6672053178D0073B544 /* WebViewFactory.swift in Sources */, 6932AA671FB9F69300382CF7 /* Swap.swift in Sources */, FF98E5FD204B68540026ADEC /* BarChartConfiguration.swift in Sources */, 6932AA711FB9F69300382CF7 /* CY.swift in Sources */, diff --git a/tutorial/VisualizingQuantumState-Linux/.gitignore b/tutorial/VisualizingQuantumState-Linux/.gitignore new file mode 100644 index 0000000..02c0875 --- /dev/null +++ b/tutorial/VisualizingQuantumState-Linux/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj diff --git a/tutorial/VisualizingQuantumState-Linux/Package.swift b/tutorial/VisualizingQuantumState-Linux/Package.swift new file mode 100644 index 0000000..04cca3f --- /dev/null +++ b/tutorial/VisualizingQuantumState-Linux/Package.swift @@ -0,0 +1,19 @@ +// swift-tools-version:4.0 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "VisualizingQuantumState-Linux", + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(url: "../../", from: "0.1.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target( + name: "VisualizingQuantumState-Linux", + dependencies: ["qiskit"]), + ] +) diff --git a/tutorial/VisualizingQuantumState-Linux/README.md b/tutorial/VisualizingQuantumState-Linux/README.md new file mode 100644 index 0000000..86d8ea0 --- /dev/null +++ b/tutorial/VisualizingQuantumState-Linux/README.md @@ -0,0 +1,17 @@ +# Visualizing a Quantum State (for Linux) +The latest version of this demo app is available on [QISKit Swift Tutorial](https://github.com/QISKit/qiskit-sdk-swift/tree/master/tutorial). + +## Acknowledgement +This app is based on the playground with the same name located [here](https://github.com/QISKit/qiskit-sdk-swift/tree/master/tutorial/VisualizingQuantumState.playground), which in turn is based on [this notebook on QISKit Python Tutorial](https://github.com/QISKit/qiskit-tutorial/blob/master/1_introduction/visualizing_quantum_state.ipynb). + +## Usage + +``` +swift run +``` + +This app will present a window with multiple tabs, one for each graph used to visualize information about the quantum state. + +For a better understanding of what is going on, we recommend to study the documentation in the [notebook mentioned before](https://github.com/QISKit/qiskit-tutorial/blob/master/1_introduction/visualizing_quantum_state.ipynb). + +Each graph is a GTK Widget, check [this file](https://github.com/QISKit/qiskit-sdk-swift/tree/master/tutorial/VisualizingQuantumState-Linux/Sources/VisualizingQuantumState-Linux/widgets.swift) to know how to handle a widget in your Swift app for Linux. \ No newline at end of file diff --git a/tutorial/VisualizingQuantumState-Linux/Sources/VisualizingQuantumState-Linux/main.swift b/tutorial/VisualizingQuantumState-Linux/Sources/VisualizingQuantumState-Linux/main.swift new file mode 100644 index 0000000..3d138d8 --- /dev/null +++ b/tutorial/VisualizingQuantumState-Linux/Sources/VisualizingQuantumState-Linux/main.swift @@ -0,0 +1,175 @@ +// 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 qiskit +import CWebkitGtk_Linux +import Dispatch +import Foundation + +gtk_init(nil, nil) + +let window = window_widget() +let notebook = notebook_widget() +add_widget(notebook, to: window) + +let histogram_semaphore = DispatchSemaphore(value: 1) +let state_semaphore = DispatchSemaphore(value: 1) + +do { + let Q_program = try QuantumProgram() + let n = 3 // number of qubits + let q = try Q_program.create_quantum_register("q", n) + let c = try Q_program.create_classical_register("c", n) + + // quantum circuit to make a GHZ state + let ghz_name = "ghz" + let ghz = try Q_program.create_circuit(ghz_name, [q], [c]) + try ghz.h(q[0]) + try ghz.cx(q[0], q[1]) + try ghz.cx(q[0], q[2]) + try ghz.s(q[0]) + try ghz.measure(q[0], c[0]) + try ghz.measure(q[1], c[1]) + try ghz.measure(q[2], c[2]) + print(ghz.qasm()) + + // quantum circuit to make a superpostion state + let superposition_name = "superposition" + let superposition = try Q_program.create_circuit(superposition_name, [q], [c]) + try superposition.h(q) + try superposition.s(q[0]) + try superposition.measure(q[0], c[0]) + try superposition.measure(q[1], c[1]) + try superposition.measure(q[2], c[2]) + print(superposition.qasm()) + + let circuits = [ghz_name, superposition_name] + + // execute the quantum circuit + histogram_semaphore.wait() + var backend = "local_qasm_simulator" // the device to run on + Q_program.execute(circuits, backend: backend, shots: 1000) { (result) in + if let error = result.get_error() { + print(error) + + histogram_semaphore.signal() + + return + } + + do { + let ghz_histogram = plot_histogram(try result.get_counts(ghz_name)) + insert_page(ghz_histogram, in: notebook, position: 0, title: "Ghz Hist.") + + let superposition_histogram = plot_histogram(try result.get_counts(superposition_name)) + insert_page(superposition_histogram, in: notebook, position: 1, title: "Super. Hist.") + } catch { + print(error) + } + + histogram_semaphore.signal() + } + + // execute the quantum circuit + state_semaphore.wait() + backend = "local_unitary_simulator" // the device to run on + Q_program.execute(circuits, backend: backend, shots: 1000) { (result) in + if let error = result.get_error() { + print(error) + + state_semaphore.signal() + + return + } + + let groundRows = Int(truncating: NSDecimalNumber(decimal: Decimal(pow(Double(2), Double(n))))) + var ground = Matrix(repeating: Complex(integerLiteral: 0), rows: groundRows, cols: 1) + ground[0, 0] = Complex(integerLiteral: 1) + + do { + guard let ghz_unitary = try result.get_data(ghz_name)["unitary"] as? Matrix, + let superposition_unitary = try result.get_data(superposition_name)["unitary"] as? Matrix else { + print("Unable to get unitary matrices") + + state_semaphore.signal() + + return + } + + let state_ghz = ghz_unitary.dot(ground) + let flatten_state_ghz = state_ghz.flattenRow() + let rho_ghz = flatten_state_ghz.outer(flatten_state_ghz.conjugate()) + + let ghz_city = plot_state(rho_ghz, .city) + insert_page(ghz_city, in: notebook, position: 2, title: "Ghz City") + + let ghz_paulivec = plot_state(rho_ghz, .paulivec) + insert_page(ghz_paulivec, in: notebook, position: 3, title: "Ghz Pauli.") + + let ghz_qsphere = plot_state(rho_ghz, .qsphere) + insert_page(ghz_qsphere, in: notebook, position: 4, title: "Ghz Qsphere") + + let state_superposition = superposition_unitary.dot(ground) + let flatten_state_superposition = state_superposition.flattenRow() + let rho_superposition = flatten_state_superposition.outer(flatten_state_superposition.conjugate()) + + let superposition_city = plot_state(rho_superposition, .city) + insert_page(superposition_city, in: notebook, position: 5, title: "Super. City") + + let superposition_paulivec = plot_state(rho_superposition, .paulivec) + insert_page(superposition_paulivec, in: notebook, position: 6, title: "Super. Pauli.") + + let superposition_qsphere = plot_state(rho_superposition, .qsphere) + insert_page(superposition_qsphere, in: notebook, position: 7, title: "Super. Qsphere") + + let superposition_bloch = plot_state(rho_superposition, .bloch) + insert_page(superposition_bloch, in: notebook, position: 8, title: "Super. Bloch") + + let rho_superposition_by_half = rho_superposition.mult(Complex(0.5, 0)) + let rho_ghz_by_half = rho_ghz.mult(Complex(0.5, 0)) + let added_rho = try rho_superposition_by_half.add(rho_ghz_by_half) + let added_qsphere = plot_state(added_rho, .qsphere) + insert_page(added_qsphere, in: notebook, position: 9, title: "Added Qsphere") + } catch { + print(error) + } + + state_semaphore.signal() + } +} catch { + print(error) +} + +let handler: @convention(c) (UnsafeMutableRawPointer, UnsafeMutableRawPointer) -> Void = { sender, data in + gtk_main_quit() + exit(0) +} +g_signal_connect_data(window, "destroy", unsafeBitCast(handler, to: GCallback.self), nil, nil, G_CONNECT_AFTER) + +DispatchQueue.global().async { + histogram_semaphore.wait() + histogram_semaphore.signal() + + state_semaphore.wait() + state_semaphore.signal() + + DispatchQueue.main.async { + gtk_widget_show_all(window) + + gtk_main() + } +} + +RunLoop.main.run() diff --git a/tutorial/VisualizingQuantumState-Linux/Sources/VisualizingQuantumState-Linux/widgets.swift b/tutorial/VisualizingQuantumState-Linux/Sources/VisualizingQuantumState-Linux/widgets.swift new file mode 100644 index 0000000..3544428 --- /dev/null +++ b/tutorial/VisualizingQuantumState-Linux/Sources/VisualizingQuantumState-Linux/widgets.swift @@ -0,0 +1,55 @@ +// 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 CWebkitGtk_Linux + +func window_widget() -> UnsafeMutablePointer { + let widget = gtk_window_new(GTK_WINDOW_TOPLEVEL)! + + let window = UnsafeMutablePointer(OpaquePointer(widget)) + let window_width = gint(800) + let window_height = gint(700) + gtk_window_set_default_size(window, window_width, window_height) + + return widget +} + +func notebook_widget() -> UnsafeMutablePointer { + return gtk_notebook_new() +} + +func scrolled_window_widget() -> UnsafeMutablePointer { + return gtk_scrolled_window_new(nil, nil)! +} + +func add_widget(_ widget: UnsafeMutablePointer, to container: UnsafeMutablePointer) { + let internalContainer = UnsafeMutablePointer(OpaquePointer(container)) + + gtk_container_add(internalContainer, widget) +} + +func label_widget(text: String) -> UnsafeMutablePointer { + return gtk_label_new (text) +} + +func insert_page(_ widget: UnsafeMutablePointer, in container: UnsafeMutablePointer, position: Int, title: String) { + let notebook = UnsafeMutablePointer(OpaquePointer(container)) + let label = label_widget(text: title) + + let scrolledWindow = scrolled_window_widget() + add_widget(widget, to: scrolledWindow) + + gtk_notebook_insert_page(notebook, scrolledWindow, label, gint(position)) +}