We are in the process of making this properly supported, but in the meantime, give this function a shot (you need to build Cadabra from source for this, the functionality is not yet in any of the binary packages):

```
def expand_conjugate(ex):
tst:= (A??)^{\dagger};
for node in ex:
if tst.matches( node ):
rep=$P$
lst=[]
for prod in node["\\prod"]:
for factor in prod.factors():
lst.append($ @(factor) $)
for factor in list(reversed(lst)):
rep.top().append_child($ @(factor)^{\dagger} $)
rep.top().name=r"\prod"
node.replace(rep)
return ex
```

If you stick the above in a cell and evaluate it, you can then do

```
\dagger::Symbol;
ex:= (A B C)^{\dagger} + Q + (D E)^{\dagger};
expand_conjugate(ex);
```

to produce

$$C^{\dagger} B^{\dagger} A^{\dagger} + Q + E^{\dagger} D^{\dagger}$$

There will be better support for generic conjugation operations in Cadabra soon.

For the other two lines, try simple substitution with a rule of the type

```
rl:= { (A?^{\dagger})^{\dagger} = A?,
( (A??)^{\dagger} )^{\dagger} = A??,
A?^{\dagger} A? = 1,
A? A^{\dagger} = 1,
(A??)^{\dagger} A?? = 1,
A?? (A??)^{\dagger} = 1 };
```

You can then do e.g.

```
\dagger::Symbol;
{A,B,U}::NonCommuting;
ex:= ( U^{\dagger} )^{\dagger} + U^{\dagger} U
+ (A B)^{\dagger} + ( (A B)^{\dagger} )^{\dagger};
substitute(ex, rl);
```

Hope this helps.