The following code
(declare-fun f (Int) Real)
(declare-fun g (Int) Real)
(declare-const x Int)
(declare-const y Int)
(assert (= (* (f x) (g y)) 1.0))
(check-sat)
(get-model)
returns "unknown", even though there is an obvious solution. Eliminating arguments to f and g (effectively making them constants?) results in "sat" with expected assignments. I guess, my question is: what is special about arithmetic with uninterpreted functions?
BTW, replacing * with + also results in "sat", so the issue is not about uninterpreted functions, per se, but about how they are combined.
Additional thoughts
Making the domain (very) finite does not help, e.g.,
(declare-fun f (Bool) Real)
(declare-fun g (Bool) Real)
(declare-const x Bool)
(declare-const y Bool)
(assert (= (* (f x) (g y)) 1.0))
(check-sat)
(get-model)
returns "unknown". This is odd given that f:Bool->Real is essentially just two variables f(False) and f(True) (of course, the solver has to recognize this).
Inability to handle non-linear arithmetic over real-valued uninterpreted functions is a very severe limitation because arrays are implemented as uninterpreted functions. So, for example,
(declare-const a (Array Int Real))
(assert (= (* (select a 1) (select a 1)) 1))
(check-sat)
(get-model)
returns "unknown". In other words, any non-linear algebraic expression on real array elements involving multiplication is unsolvable:'(