{"id":22891519,"url":"https://github.com/renmusxd/rustqip","last_synced_at":"2025-04-04T07:07:59.862Z","repository":{"id":41476667,"uuid":"185723988","full_name":"Renmusxd/RustQIP","owner":"Renmusxd","description":"Quantum computing using rust. Efficient and a borrow-checked no cloning theorem!","archived":false,"fork":false,"pushed_at":"2024-03-05T06:47:24.000Z","size":690,"stargazers_count":224,"open_issues_count":30,"forks_count":18,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-08-05T10:08:48.123Z","etag":null,"topics":["qip","quantum-computing","rust","rust-lang"],"latest_commit_sha":null,"homepage":"https://docs.rs/qip/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Renmusxd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-09T04:04:44.000Z","updated_at":"2024-07-30T17:09:30.000Z","dependencies_parsed_at":"2024-01-13T12:22:17.619Z","dependency_job_id":"967b91b1-316d-407d-aa71-6d6ab5c0f3f7","html_url":"https://github.com/Renmusxd/RustQIP","commit_stats":{"total_commits":253,"total_committers":6,"mean_commits":"42.166666666666664","dds":0.09881422924901184,"last_synced_commit":"bce26b14b2c147c7ff556dd3e44d01d907b21fe4"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Renmusxd%2FRustQIP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Renmusxd%2FRustQIP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Renmusxd%2FRustQIP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Renmusxd%2FRustQIP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Renmusxd","download_url":"https://codeload.github.com/Renmusxd/RustQIP/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245978272,"owners_count":20703677,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["qip","quantum-computing","rust","rust-lang"],"created_at":"2024-12-13T22:34:05.183Z","updated_at":"2025-03-28T06:08:19.987Z","avatar_url":"https://github.com/Renmusxd.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RustQIP\n\nQuantum Computing library leveraging graph building to build efficient quantum circuit simulations.\n\n[![qip on crates.io](https://img.shields.io/crates/v/qip.svg)](https://crates.io/crates/qip)\n[![qip docs](https://img.shields.io/badge/docs-docs.rs-orange.svg)](https://docs.rs/qip)\n[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)\n\nSee all the examples in the [examples directory](https://github.com/Renmusxd/RustQIP/tree/master/qip/examples).\n\n*PRs welcome*\n\nRust is a great language for quantum computing with gate models because the borrow checker\nis very similar to the [No-cloning theorem](https://wikipedia.org/wiki/No-cloning_theorem).\n\nSee all the examples in the [examples directory](https://github.com/Renmusxd/RustQIP/tree/master/qip/examples) of the Github\nrepository.\n\n# Example (CSWAP)\n\nHere's an example of a small circuit where two groups of Registers are swapped conditioned on a\nthird. This circuit is very small, only three operations plus a measurement, so the boilerplate\ncan look quite large in comparison, but that setup provides the ability to construct circuits\neasily and safely when they do get larger.\n\n```rust\nuse qip::prelude::*;\nuse std::num::NonZeroUsize;\n\n// Make a new circuit builder.\nlet mut b = LocalBuilder::\u003cf64\u003e::default();\nlet n = NonZeroUsize::new(3).unwrap();\n\n// Make three registers of sizes 1, 3, 3 (7 qubits total).\nlet q = b.qubit();  // Same as b.register(1)?;\nlet ra = b.register(n);\nlet rb = b.register(n);\n\n// Define circuit\n// First apply an H to q\nlet q = b.h(q);\n// Then swap ra and rb, conditioned on q.\nlet mut cb = b.condition_with(q);\nlet (ra, rb) = cb.swap(ra, rb) ?;\nlet q = cb.dissolve();\n// Finally apply H to q again.\nlet q = b.h(q);\n\n// Add a measurement to the first qubit, save a reference so we can get the result later.\nlet (q, m_handle) = b.measure(q);\n\n// Now q is the end result of the above circuit, and we can run the circuit by referencing it.\n\n// Run circuit with a given precision.\nlet (_, measured) = b.calculate_state_with_init([( \u0026 ra, 0b000), ( \u0026 rb, 0b001)]);\n\n// Lookup the result of the measurement we performed using the handle, and the probability\n// of getting that measurement.\nlet (result, p) = measured.get_measurement(m_handle);\n\n// Print the measured result\nprintln!(\"Measured: {:?} (with chance {:?})\", result, p);\n```\n\n# The Program Macro\n\nWhile the borrow checker included in rust is a wonderful tool for checking that our registers\nare behaving, it can be cumbersome. For that reason qip also includes a macro which provides an\nAPI similar to that which you would see in quantum computing textbooks.\nThis is guarded behind the `macros` feature.\n\n```rust\nuse qip::prelude::*;\nuse std::num::NonZeroUsize;\nuse qip_macros::program;\n\nfn gamma\u003cB\u003e(b: \u0026mut B, ra: B::Register, rb: B::Register) -\u003e CircuitResult\u003c(B::Register, B::Register)\u003e\n    where B: AdvancedCircuitBuilder\u003cf64\u003e\n{\n    let (ra, rb) = b.toffoli(ra, rb)?;\n    let (rb, ra) = b.toffoli(rb, ra)?;\n    Ok((ra, rb))\n}\n\nlet n = NonZeroUsize::new(3).unwrap();\nlet mut b = LocalBuilder::default();\nlet ra = b.register(n);\nlet rb = b.register(n);\n\nlet (ra, rb) = program!(\u0026mut b; ra, rb;\n    // Applies gamma to |ra[0] ra[1]\u003e|ra[2]\u003e\n    gamma ra[0..2], ra[2];\n    // Applies gamma to |ra[0] rb[0]\u003e|ra[2]\u003e\n    // Notice ra[0] and rb[0] are grouped by brackets.\n    gamma [ra[0], rb[0]], ra[2];\n    // Applies gamma to |ra[0]\u003e|rb[0] ra[2]\u003e\n    gamma ra[0], [rb[0], ra[2]];\n    // Applies gamma to |ra[0] ra[1]\u003e|ra[2]\u003e if rb == |111\u003e\n    control gamma rb, ra[0..2], ra[2];\n    // Applies gamma to |ra[0] ra[1]\u003e|ra[2]\u003e if rb == |110\u003e (rb[0] == |0\u003e, rb[1] == 1, ...)\n    control(0b110) gamma rb, ra[0..2], ra[2];\n)?;\n```\n\nWe can also apply this to functions which take other arguments. Here `gamma` takes a boolean\nargument `skip` which is passed in before the registers.\n*The arguments to functions in the program macro may not reference the input registers*\n\n```rust\nuse qip::prelude::*;\nuse std::num::NonZeroUsize;\nuse qip_macros::program;\n\nfn gamma\u003cB\u003e(b: \u0026mut B, skip: bool, ra: B::Register, rb: B::Register) -\u003e CircuitResult\u003c(B::Register, B::Register)\u003e\n    where B: AdvancedCircuitBuilder\u003cf64\u003e\n{\n    let (ra, rb) = b.toffoli(ra, rb)?;\n    let (rb, ra) = if skip {\n        b.toffoli(rb, ra)?\n    } else {\n        (rb, ra)\n    };\n    Ok((ra, rb))\n}\nlet n = NonZeroUsize::new(3).unwrap();\nlet mut b = LocalBuilder::default();\nlet ra = b.register(n);\nlet rb = b.register(n);\n\nlet (ra, rb) = program!(\u0026mut b; ra, rb;\n    gamma(true) ra[0..2], ra[2];\n    gamma(0 == 1) ra[0..2], ra[2];\n)?;\n```\n\n# The Invert Macro\n\nIt's often useful to define functions of registers as well as their inverses, the `#[invert]`\nmacro automates much of this process.\n\n```rust\nuse qip::prelude::*;\nuse std::num::NonZeroUsize;\nuse qip_macros::*;\nuse qip::inverter::Invertable;\n\n// Make gamma and its inverse: gamma_inv\n#[invert(gamma_inv)]\nfn gamma\u003cB\u003e(b: \u0026mut B, ra: B::Register, rb: B::Register) -\u003e CircuitResult\u003c(B::Register, B::Register)\u003e\n    where B: AdvancedCircuitBuilder\u003cf64\u003e + Invertable\u003cSimilarBuilder=B\u003e\n{\n    let (ra, rb) = b.toffoli(ra, rb)?;\n    let (rb, ra) = b.toffoli(rb, ra)?;\n    Ok((ra, rb))\n}\n\nlet n = NonZeroUsize::new(3).unwrap();\nlet mut b = LocalBuilder::default();\nlet ra = b.register(n);\nlet rb = b.register(n);\n\nlet (ra, rb) = program!(\u0026mut b; ra, rb;\n    gamma ra[0..2], ra[2];\n    gamma_inv ra[0..2], ra[2];\n)?;\n```\n\nTo invert functions with additional arguments, we must list the non-register arguments.\n\n```rust\nuse qip::prelude::*;\nuse std::num::NonZeroUsize;\nuse qip_macros::*;\nuse qip::inverter::Invertable;\n\n// Make gamma and its inverse: gamma_inv\n#[invert(gamma_inv, skip)]\nfn gamma\u003cB\u003e(b: \u0026mut B, skip: bool, ra: B::Register, rb: B::Register) -\u003e CircuitResult\u003c(B::Register, B::Register)\u003e\n    where B: AdvancedCircuitBuilder\u003cf64\u003e + Invertable\u003cSimilarBuilder=B\u003e\n{\n    let (ra, rb) = b.toffoli(ra, rb)?;\n    let (rb, ra) = if skip {\n        b.toffoli(rb, ra)?\n    } else {\n        (rb, ra)\n    };\n    Ok((ra, rb))\n}\n\nlet n = NonZeroUsize::new(3).unwrap();\nlet mut b = LocalBuilder::default();\nlet ra = b.register(n);\nlet rb = b.register(n);\n\nlet (ra, rb) = program!(\u0026mut b; ra, rb;\n    gamma(true) ra[0..2], ra[2];\n    gamma_inv(true) ra[0..2], ra[2];\n)?;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenmusxd%2Frustqip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frenmusxd%2Frustqip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenmusxd%2Frustqip/lists"}