Skip to content

🐛 MLIR Module equivalence verifier fails for equivalent circuits with different insertion order #1752

@li-mingbao

Description

@li-mingbao

System and Environment Information

  • mlir/llvm version 22.1.5
  • OS: Ubuntu 22.04

Bug Description

The current module equivalence checker in the MLIR tests fail if the insertion order of qubits to the registers are different at the end. The areModulesEquivalentWithPermutations function should still succeed even if the insertion order at the end is different, as the resulting circuit is still equivalent.

Steps to Reproduce

The following two modules are not equivalent according to the verifier:

 module {                                                                                                             
   func.func @main() -> i64 attributes {passthrough = ["entry_point"]} {                                              
     %c0_i64 = arith.constant 0 : i64                                                                                 
     %c1 = arith.constant 1 : index                                                                                   
     %c0 = arith.constant 0 : index                                                                                   
     %c2 = arith.constant 2 : index                                                                                   
     %0 = qtensor.alloc(%c2) : tensor<2x!qco.qubit>                                                                   
     %out_tensor, %result = qtensor.extract %0[%c0] : tensor<2x!qco.qubit>                                            
     %out_tensor_0, %result_1 = qtensor.extract %out_tensor[%c1] : tensor<2x!qco.qubit>                               
     %1 = qco.alloc : !qco.qubit                                                                                      
     %2 = qco.h %1 : !qco.qubit -> !qco.qubit                                                                         
     %controls_out, %targets_out = qco.ctrl(%2) targets (%arg0 = %result) {                                           
       %5 = qco.x %arg0 : !qco.qubit -> !qco.qubit                                                                    
       qco.yield %5 : !qco.qubit                                                                                      
     } : ({!qco.qubit}, {!qco.qubit}) -> ({!qco.qubit}, {!qco.qubit})                                                 
     %controls_out_2, %targets_out_3 = qco.ctrl(%controls_out) targets (%arg0 = %result_1) {                          
       %5 = qco.x %arg0 : !qco.qubit -> !qco.qubit                                                                    
       qco.yield %5 : !qco.qubit                                                                                      
     } : ({!qco.qubit}, {!qco.qubit}) -> ({!qco.qubit}, {!qco.qubit})                                                 
     qco.sink %controls_out_2 : !qco.qubit                                                                            
     %3 = qtensor.insert %targets_out_3 into %out_tensor_0[%c1] : tensor<2x!qco.qubit>                                
     %4 = qtensor.insert %targets_out into %3[%c0] : tensor<2x!qco.qubit>                                             
     qtensor.dealloc %4 : tensor<2x!qco.qubit>                                                                        
     return %c0_i64 : i64                                                                                             
   }                                                                                                                  
 } 
module {                                                                                                             
   func.func @main() -> i64 attributes {passthrough = ["entry_point"]} {                                              
     %c0_i64 = arith.constant 0 : i64                                                                                 
     %c1 = arith.constant 1 : index                                                                                   
     %c0 = arith.constant 0 : index                                                                                   
     %c2 = arith.constant 2 : index                                                                                   
     %0 = qtensor.alloc(%c2) : tensor<2x!qco.qubit>                                                                   
     %out_tensor, %result = qtensor.extract %0[%c0] : tensor<2x!qco.qubit>                                            
     %out_tensor_0, %result_1 = qtensor.extract %out_tensor[%c1] : tensor<2x!qco.qubit>                               
     %1 = qco.alloc : !qco.qubit                                                                                      
     %2 = qco.h %1 : !qco.qubit -> !qco.qubit                                                                         
     %controls_out, %targets_out = qco.ctrl(%2) targets (%arg0 = %result) {                                           
       %5 = qco.x %arg0 : !qco.qubit -> !qco.qubit                                                                    
       qco.yield %5 : !qco.qubit                                                                                      
     } : ({!qco.qubit}, {!qco.qubit}) -> ({!qco.qubit}, {!qco.qubit})                                                 
     %controls_out_2, %targets_out_3 = qco.ctrl(%controls_out) targets (%arg0 = %result_1) {                          
       %5 = qco.x %arg0 : !qco.qubit -> !qco.qubit                                                                    
       qco.yield %5 : !qco.qubit                                                                                      
     } : ({!qco.qubit}, {!qco.qubit}) -> ({!qco.qubit}, {!qco.qubit})                                                 
     qco.sink %controls_out_2 : !qco.qubit                                                                            
     %3 = qtensor.insert %targets_out into %out_tensor_0[%c0] : tensor<2x!qco.qubit>                                  
     %4 = qtensor.insert %targets_out_3 into %3[%c1] : tensor<2x!qco.qubit>                                           
     qtensor.dealloc %4 : tensor<2x!qco.qubit>                                                                        
     return %c0_i64 : i64                                                                                             
   }                                                                                                                  
 } 

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions