I'd think about this in terms of expression trees and context free grammars. You could say something like
EXPRESSION ::=
1 | 2 | 3
| ( EXPRESSION )+( EXPRESSION )
| ( EXPRESSION )*( EXPRESSION )
| ( EXPRESSION )^2
| sqrt( EXPRESSION )
;
This is a bit over-eager on the parentheses, so if you care about beautiful strings you may want to clean up superfluous parens in a postprocessing step, or use some more elaborate grammar with multiple non-terminals to handle those correctly.
You can start with expression trees for the three terminal rules, i.e. your three constants. Then you can consider each of the recursive rules and plug the constants you have in place of the non-terminals. So you'd generate 1+1, 1+2, 1+3, 2+1, 2+2, 2+3, 3+1, 3+2, 3+3, (1)*(1), …. Something like
for op in [plus, times]:
for lhs in expressions:
for rhs in expressions:
new_expressions.append(binaryop(lhs, op, rhs))
for op in [square, sqrt]:
for arg in expressions:
new_expressions.append(unaryop(op, arg))
Then after each such cycle, you would have to extend the set of expressions using the newly found ones. For the next round, you would try to ensure that at least one operand was generated in the last round. For binary operations, the other may have been older.
Perhaps things will become more feasible if you only use a single formula per possible value. So that once you have found that 1+3 can be used as an expression for 4, you don't do 2+2 and 2*2 and 2^2 and so on, as one way of expressing 4 is enough. Depends on the application.