Skip to content

Commit

Permalink
Add parameters for num classical params and num qubits to Type::Gate (
Browse files Browse the repository at this point in the history
#68)

* Declare builtin gate U

* Use this modification of Type::Gate to compare the implied signature from
a gate call and log errors if it does not match definition

* Log type mismatch error if gate call syntax is used, but the apparent gate
is of a different type.

Closes #24
  • Loading branch information
jlapeyre authored Jan 21, 2024
1 parent b876609 commit b712853
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 10 deletions.
2 changes: 2 additions & 0 deletions crates/oq3_semantics/src/semantic_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub enum SemanticErrorKind {
IncompatibleTypesError,
MutateConstError,
IncludeNotInGlobalScopeError,
NumGateParamsError,
NumGateQubitsError,
}

#[derive(Clone, Debug)]
Expand Down
2 changes: 2 additions & 0 deletions crates/oq3_semantics/src/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,12 @@ impl SymbolTable {
all_symbols: Vec::<Symbol>::new(),
};
symbol_table.enter_scope(ScopeType::Global);
// Define global, built-in constants
for const_name in ["pi", "π", "euler", "ℇ", "tau", "τ"] {
let _ =
symbol_table.new_binding(const_name, &Type::Float(Some(64), types::IsConst::True));
}
let _ = symbol_table.new_binding("U", &Type::Gate(3, 1)); // U(a, b, c) q
symbol_table
}

Expand Down
40 changes: 34 additions & 6 deletions crates/oq3_semantics/src/syntax_to_semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,6 @@ fn from_item(item: synast::Item, context: &mut Context) -> Option<asg::Stmt> {
// Gate definition
synast::Item::Gate(gate) => {
let name_node = gate.name().unwrap();
let gate_name_symbol_id =
context.new_binding(name_node.string().as_ref(), &Type::Gate, &name_node);

// Here are three ways to manage the context.

// Make some bindings and push and pop the scope automatically.
Expand Down Expand Up @@ -459,14 +456,26 @@ fn from_item(item: synast::Item, context: &mut Context) -> Option<asg::Stmt> {
let qubits = bind_parameter_list(gate.qubit_params(), &Type::Qubit, context).unwrap();
let block = from_block_expr(gate.body().unwrap(), context);
);
let num_params = match params {
Some(ref params) => params.len(),
None => 0,
};
let gate_name_symbol_id = context.new_binding(
name_node.string().as_ref(),
&Type::Gate(
num_params.try_into().unwrap(),
qubits.len().try_into().unwrap(),
),
&name_node,
);

Some(asg::GateDeclaration::new(gate_name_symbol_id, params, qubits, block).to_stmt())
}

synast::Item::GateCallStmt(gate_call) => {
// Warning, I think map overlooks None. which can cause a bug, in the present case.
// Because None means a coding error upstream. Better to blow up here.
let gate_operands = gate_call
let gate_operands: Vec<_> = gate_call
.qubit_list()
.unwrap()
.gate_operands()
Expand All @@ -476,12 +485,31 @@ fn from_item(item: synast::Item, context: &mut Context) -> Option<asg::Stmt> {
let param_list = gate_call
.arg_list()
.map(|ex| inner_expression_list(ex.expression_list().unwrap(), context));
let num_params = match param_list {
Some(ref params) => params.len(),
None => 0,
};
let gate_id = gate_call.identifier();
// FIXME: make sure we are efficient with strings
let gate_name = gate_call.identifier().unwrap().text().to_string();
let (symbol_result, _typ) = context
.lookup_gate_symbol(gate_name.as_ref(), &gate_id.unwrap())
let (symbol_result, gate_type) = context
.lookup_gate_symbol(gate_name.as_ref(), gate_id.as_ref().unwrap())
.as_tuple();
if matches!(gate_type, Type::Gate(_, _)) {
let (def_num_params, def_num_qubits) = match gate_type {
Type::Gate(np, nq) => (np, nq),
_ => (0, 0),
};
if def_num_params != num_params.try_into().unwrap() {
context.insert_error(NumGateParamsError, &gate_call);
}
if def_num_qubits != gate_operands.len().try_into().unwrap() {
context.insert_error(NumGateQubitsError, &gate_call);
}
} else if symbol_result.is_ok() {
// If symbol_result.is_err then we have already logged UndefGateError.
context.insert_error(IncompatibleTypesError, &gate_id.unwrap());
}
Some(asg::Stmt::GateCall(asg::GateCall::new(
symbol_result,
param_list,
Expand Down
4 changes: 2 additions & 2 deletions crates/oq3_semantics/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ pub enum Type {
DurationArray(ArrayDims),

// Other
Gate, // <-- this type seems anomalous
Range, // temporary placeholder, perhaps
Gate(i32, i32), // (num classical args, num quantum args)
Range, // temporary placeholder, perhaps
Void,
ToDo, // not yet implemented
// Undefined means a type that is erroneously non-existent. This is not the same as unknown.
Expand Down
2 changes: 1 addition & 1 deletion crates/oq3_semantics/tests/ast_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use oq3_semantics::asg;
use oq3_semantics::symbols;
use oq3_semantics::types;

const NUM_BUILTIN_CONSTS: usize = 6;
const NUM_BUILTIN_CONSTS: usize = 7;

//
// TExpr
Expand Down
2 changes: 1 addition & 1 deletion crates/oq3_semantics/tests/symbol_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use oq3_semantics::symbols;
use oq3_semantics::types;

const NUM_BUILTIN_CONSTS: usize = 6;
const NUM_BUILTIN_CONSTS: usize = 7;

//
// Test API of symbols and symbol tables
Expand Down

0 comments on commit b712853

Please sign in to comment.