Contract tensors by multiplying matrix representations. tensor_3(map_1, map_2) := alpha * tensor_1(notcontract_1, contract_1) * tensor_2(contract_2, notcontract_2) + beta * tensor_3(map_1, map_2)
note 1: block sizes of the corresponding indices need to be the same in all tensors.
note 2: for best performance the tensors should have been created in matrix layouts compatible with the contraction, e.g. tensor_1 should have been created with either map1_2d == contract_1 and map2_2d == notcontract_1 or map1_2d == notcontract_1 and map2_2d == contract_1 (the same with tensor_2 and contract_2 / notcontract_2 and with tensor_3 and map_1 / map_2). Furthermore the two largest tensors involved in the contraction should map both to either tall or short matrices: the largest matrix dimension should be "on the same side" and should have identical distribution (which is always the case if the distributions were obtained with dbcsr_t_default_distvec).
note 3: if the same tensor occurs in multiple contractions, a different tensor object should be created for each contraction and the data should be copied between the tensors by use of dbcsr_t_copy. If the same tensor object is used in multiple contractions, matrix layouts are not compatible for all contractions (see note 2).
note 4: automatic optimizations are enabled by using the feature of batched contraction, see dbcsr_t_batched_contract_init, dbcsr_t_batched_contract_finalize. The arguments bounds_1, bounds_2, bounds_3 give the index ranges of the batches.
Type  Intent  Optional  Attributes  Name  

type(dbcsr_scalar_type),  intent(in)  ::  alpha  
type(dbcsr_t_type),  intent(inout),  TARGET  ::  tensor_1 
first tensor (in) 

type(dbcsr_t_type),  intent(inout),  TARGET  ::  tensor_2 
second tensor (in) 

type(dbcsr_scalar_type),  intent(in)  ::  beta  
type(dbcsr_t_type),  intent(inout),  TARGET  ::  tensor_3 
contracted tensor (out) 

integer,  intent(in),  DIMENSION(:)  ::  contract_1 
indices of tensor_1 to contract 

integer,  intent(in),  DIMENSION(:)  ::  notcontract_1 
indices of tensor_1 not to contract 

integer,  intent(in),  DIMENSION(:)  ::  contract_2 
indices of tensor_2 to contract (1:1 with contract_1) 

integer,  intent(in),  DIMENSION(:)  ::  notcontract_2 
indices of tensor_2 not to contract 

integer,  intent(in),  DIMENSION(:)  ::  map_1 
which indices of tensor_3 map to noncontracted indices of tensor_1 (1:1 with notcontract_1) 

integer,  intent(in),  DIMENSION(:)  ::  map_2 
which indices of tensor_3 map to noncontracted indices of tensor_2 (1:1 with notcontract_2) 

integer,  intent(in),  optional,  DIMENSION(2, SIZE(contract_1))  ::  bounds_1 
bounds corresponding to contract_1 AKA contract_2: start and end index of an index range over which to contract. For use in batched contraction. 
integer,  intent(in),  optional,  DIMENSION(2, SIZE(notcontract_1))  ::  bounds_2 
bounds corresponding to notcontract_1: start and end index of an index range. For use in batched contraction. 
integer,  intent(in),  optional,  DIMENSION(2, SIZE(notcontract_2))  ::  bounds_3 
bounds corresponding to notcontract_2: start and end index of an index range. For use in batched contraction. 
logical,  intent(in),  optional  ::  optimize_dist 
Whether distribution should be optimized internally. In the current implementation this guarantees optimal parameters only for dense matrices. 

type(dbcsr_t_pgrid_type),  intent(out),  optional,  POINTER  ::  pgrid_opt_1 
Optionally return optimal process grid for tensor_1. This can be used to choose optimal process grids for subsequent tensor contractions with tensors of similar shape and sparsity. Under some conditions, pgrid_opt_1 can not be returned, in this case the pointer is not associated. 
type(dbcsr_t_pgrid_type),  intent(out),  optional,  POINTER  ::  pgrid_opt_2 
Optionally return optimal process grid for tensor_2. 
type(dbcsr_t_pgrid_type),  intent(out),  optional,  POINTER  ::  pgrid_opt_3 
Optionally return optimal process grid for tensor_3. 
real(kind=real_8),  intent(in),  optional  ::  filter_eps 
As in DBCSR mm 

integer(kind=int_8),  intent(out),  optional  ::  flop 
As in DBCSR mm 

logical,  intent(in),  optional  ::  move_data 
memory optimization: transfer data such that tensor_1 and tensor_2 are empty on return 

logical,  intent(in),  optional  ::  retain_sparsity 
enforce the sparsity pattern of the existing tensor_3; default is no 

integer,  intent(in),  optional  ::  unit_nr 
output unit for logging set it to 1 on ranks that should not write (and any valid unit number on ranks that should write output) if 0 on ALL ranks, no output is written 

logical,  intent(in),  optional  ::  log_verbose 
verbose logging (for testing only) 