def solve_all(self, f1, trace): """ Returns an upperset in UR. You want to project it to R1 to use as the output. """ dp0 = self.dp1 R = dp0.get_res_space() R1 = R[0] UR = UpperSets(R) # we consider a set of iterates # we start from the bottom trace.log('Iterating in UR = %s' % UR.__str__()) s0 = R.Us(R.get_minimal_elements()) S = [ KleeneIteration(s=s0, s_converged=R.Us(set()), r=upperset_project(s0, 0), r_converged=R1.Us(set())) ] for i in range(1, 1000000): # XXX with trace.iteration(i) as t: si_prev = S[-1].s si_next, converged = solve_f_iterate(dp0, f1, R, si_prev, t) iteration = KleeneIteration(s=si_next, s_converged=converged, r=upperset_project(si_next, 0), r_converged=upperset_project( converged, 0)) S.append(iteration) t.log('R = %s' % UR.format(si_next)) if do_extra_checks(): try: UR.check_leq(si_prev, si_next) except NotLeq as e: msg = 'Loop iteration invariant not satisfied.' raise_wrapped(Exception, e, msg, si_prev=si_prev, si_next=si_next, dp=self.dp1) t.values(state=S[-1]) if UR.leq(si_next, si_prev): t.log('Breaking because converged (iteration %s) ' % i) #t.log(' solution is %s' % (UR.format(sip))) # todo: add reason why interrupted break trace.values(type='loop2', UR=UR, R=R, dp=self, iterations=S) res_all = S[-1].s res_r1 = upperset_project(res_all, 0) result = dict(res_all=res_all, res_r1=res_r1) return result
def solve_stats(ndp): res = {} query = { "endurance": "1.5 hour", "velocity": "1 m/s", "extra_power": " 1 W", "extra_payload": "100 g", "num_missions": "100 []", } context = Context() f = convert_string_query(ndp=ndp, query=query, context=context) dp0 = ndp.get_dp() dpL, dpU = get_dp_bounds(dp0, nl=1, nu=1) F = dp0.get_fun_space() F.belongs(f) from mcdp import logger traceL = Tracer(logger=logger) resL = dpL.solve_trace(f, traceL) traceU = Tracer(logger=logger) resU = dpU.solve_trace(f, traceU) R = dp0.get_res_space() UR = UpperSets(R) print('resultsL: %s' % UR.format(resL)) print('resultsU: %s' % UR.format(resU)) res['traceL'] = traceL res['traceU'] = traceU res['resL'] = resL res['resU'] = resU res['nsteps'] = 100 return res
def solve_meat_solve_ftor(trace, ndp, dp, fg, intervals, max_steps, exp_advanced): R = dp.get_res_space() UR = UpperSets(R) # if intervals: # res = solver_iterative(dp, fg, trace) # else: if True: # if not _exp_advanced: res = dp.solve_trace(fg, trace) rnames = ndp.get_rnames() x = ", ".join(rnames) # todo: add better formatting if res.minimals: trace.log('Minimal resources needed: %s = %s' % (x, UR.format(res))) else: trace.log('This problem is unfeasible.') # else: # try: # trace = generic_solve(dp, f=fg, max_steps=max_steps) # trace.log('Iteration result: %s' % trace.result) # ss = trace.get_s_sequence() # S = trace.S # trace.log('Fixed-point iteration converged to: %s' # % S.format(ss[-1])) # R = trace.dp.get_res_space() # UR = UpperSets(R) # sr = trace.get_r_sequence() # rnames = ndp.get_rnames() # x = ", ".join(rnames) # trace.log('Minimal resources needed: %s = %s' # % (x, UR.format(sr[-1]))) # except: # raise return res, trace
def solve_meat_solve(trace, ndp, dp, fg, intervals, max_steps, exp_advanced): R = dp.get_res_space() UR = UpperSets(R) # if intervals: # res = solver_iterative(dp, fg, trace) # else: if True: # if not _exp_advanced: res = dp.solve_trace(fg, trace) rnames = ndp.get_rnames() x = ", ".join(rnames) # todo: add better formatting trace.log("Minimal resources needed: %s = %s" % (x, UR.format(res))) # else: # try: # trace = generic_solve(dp, f=fg, max_steps=max_steps) # trace.log('Iteration result: %s' % trace.result) # ss = trace.get_s_sequence() # S = trace.S # trace.log('Fixed-point iteration converged to: %s' # % S.format(ss[-1])) # R = trace.dp.get_res_space() # UR = UpperSets(R) # sr = trace.get_r_sequence() # rnames = ndp.get_rnames() # x = ", ".join(rnames) # trace.log('Minimal resources needed: %s = %s' # % (x, UR.format(sr[-1]))) # except: # raise return res, trace
def process(self, request, string, nl, nu): l = self.get_library(request) parsed = l.parse_constant(string) space = parsed.unit value = parsed.value model_name = self.get_model_name(request) library = self.get_current_library_name(request) ndp, dp = self._get_ndp_dp(library, model_name) F = dp.get_fun_space() UR = UpperSets(dp.get_res_space()) tu = get_types_universe() tu.check_leq(parsed.unit, F) f = express_value_in_isomorphic_space(parsed.unit, parsed.value, F) print('query: %s ...' % F.format(f)) from mocdp import logger tracer = Tracer(logger=logger) dpl, dpu = get_dp_bounds(dp, nl, nu) intervals = False max_steps = 10000 result_l, _trace = solve_meat_solve(tracer, ndp, dpl, f, intervals, max_steps, False) result_u, trace = solve_meat_solve(tracer, ndp, dpu, f, intervals, max_steps, False) key = (string, nl, nu) res = dict(result_l=result_l, result_u=result_u, dpl=dpl, dpu=dpu) self.solutions[key] = res res = {} e = cgi.escape res['output_space'] = e(space.__repr__() + '\n' + str(type(space))) res['output_raw'] = e(value.__repr__() + '\n' + str(type(value))) res['output_formatted'] = e(space.format(value)) res['output_result'] = 'Lower: %s\nUpper: %s' % (UR.format(result_l), UR.format(result_u)) res['output_trace'] = str(trace) encoded = "nl=%s&nu=%s&string=%s" % (nl, nu, string) res['output_image'] = 'display.png?' + encoded res['ok'] = True return res
def check_lang_singlespace3(): ndp1 = parse_ndp(""" mcdp { provides power [ S(electric_power) x W ] requires heat [ S(heat) x W ] efficiency = 0.9 [] r_heat = take(required heat, 1) f_power = take(provided power, 1) r_heat >= f_power / efficiency } """) ndp2 = parse_ndp(""" mcdp { provides power [ S(electric_power) x W ] requires heat [ S(heat) x W ] efficiency = 0.9 [] f_power = take(provided power, 1) heat >= <S(heat):*, f_power / efficiency> } """) dp1 = ndp1.get_dp() dp2 = ndp2.get_dp() R = dp1.get_res_space() print type(R), R UR = UpperSets(R) res1 = dp1.solve(('electric_power', 10.0)) res2 = dp2.solve(('electric_power', 10.0)) print UR.format(res1) print UR.format(res2)
def check_lang_singlespace3(): ndp1 = parse_ndp(""" mcdp { provides power [ S(electric_power) x W ] requires heat [ S(heat) x W ] efficiency = 0.9 [] r_heat = take(required heat, 1) f_power = take(provided power, 1) r_heat >= f_power / efficiency } """) ndp2 = parse_ndp(""" mcdp { provides power [ S(electric_power) x W ] requires heat [ S(heat) x W ] efficiency = 0.9 [] f_power = take(provided power, 1) heat >= <S(heat):*, f_power / efficiency> } """) dp1 = ndp1.get_dp() dp2 = ndp2.get_dp() R = dp1.get_res_space() print type(R), R UR = UpperSets(R) res1 = dp1.solve(('electric_power', 10.0)) res2 = dp2.solve(('electric_power', 10.0)) print UR.format(res1) print UR.format(res2)
def check_coproducts1(): parse_wrap_check('choose(a:a, b:b)', Syntax.ndpt_dp_rvalue) s = """ mcdp { provides energy [J] requires budget [$] a = mcdp { provides energy [J] requires budget [$] budget >= 5 $ energy <= 10 J } b = mcdp { provides energy [J] requires budget [$] budget >= 5 $ energy <= 50 J } c = instance choose(optionA:a, optionB:b) energy <= c.energy budget >= c.budget } """ ndp = parse_ndp(s) dp = ndp.get_dp() R = dp.get_res_space() I = dp.get_imp_space() print('R: %s' % R) print('I: %s' % I) UR = UpperSets(R) res = dp.solve(0.0) print UR.format(res) imps = dp.get_implementations_f_r(f=0.0, r=R.get_top()) print imps
def solve_all(self, f1, trace): """ Returns an upperset in UR. You want to project it to R1 to use as the output. """ dp0 = self.dp1 R = dp0.get_res_space() R1 = R[0] UR = UpperSets(R) # we consider a set of iterates # we start from the bottom trace.log('Iterating in UR = %s' % UR.__str__()) s0 = R.Us(R.get_minimal_elements()) S = [KleeneIteration(s=s0, s_converged=R.Us(set()), r=upperset_project(s0, 0), r_converged=R1.Us(set()))] for i in range(1, 1000000): # XXX with trace.iteration(i) as t: si_prev = S[-1].s si_next, converged = solve_f_iterate(dp0, f1, R, si_prev, t) iteration = KleeneIteration(s=si_next, s_converged=converged, r=upperset_project(si_next, 0), r_converged=upperset_project(converged, 0)) S.append(iteration) t.log('R = %s' % UR.format(si_next)) if do_extra_checks(): try: UR.check_leq(si_prev, si_next) except NotLeq as e: msg = 'Loop iteration invariant not satisfied.' raise_wrapped(Exception, e, msg, si_prev=si_prev, si_next=si_next, dp=self.dp1) t.values(state=S[-1]) if UR.leq(si_next, si_prev): t.log('Breaking because converged (iteration %s) ' % i) #t.log(' solution is %s' % (UR.format(sip))) # todo: add reason why interrupted break trace.values(type='loop2', UR=UR, R=R, dp=self, iterations=S) res_all = S[-1].s res_r1 = upperset_project(res_all, 0) result = dict(res_all=res_all, res_r1=res_r1) return result
def check_coproducts1(): parse_wrap_check('choose(a:a, b:b)', Syntax.ndpt_dp_rvalue) s = """ mcdp { provides energy [J] requires budget [$] a = mcdp { provides energy [J] requires budget [$] budget >= 5 $ energy <= 10 J } b = mcdp { provides energy [J] requires budget [$] budget >= 5 $ energy <= 50 J } c = instance choose(optionA:a, optionB:b) energy <= c.energy budget >= c.budget } """ ndp = parse_ndp(s) dp = ndp.get_dp() R = dp.get_res_space() I = dp.get_imp_space() print('R: %s' % R) print('I: %s' % I) UR = UpperSets(R) res = dp.solve(0.0) print UR.format(res) imps = dp.get_implementations_f_r(f=0.0, r=R.get_top()) print imps
def test_conversion(id_ndp, ndp): if '_inf' in id_ndp: # plusinvnat3b_inf print( 'Assuming that the suffix "_inf" in %r means that this will not converge' % (id_ndp)) print('Skipping this test') return try: ndp.check_fully_connected() except NotConnected: print('Skipping test_conversion because %r not connected.' % id_ndp) return dp = ndp.get_dp() F = dp.get_fun_space() R = dp.get_res_space() fs = F.get_minimal_elements() max_elements = 5 if len(fs) >= max_elements: fs = list(fs)[:max_elements] UR = UpperSets(R) for f in fs: try: res = dp.solve(f) print('%s -> %s' % (F.format(f), UR.format(res))) for r in res.minimals: imps = dp.get_implementations_f_r(f, r) print(imps) except NotSolvableNeedsApprox: break
def test_conversion(id_ndp, ndp): if '_inf' in id_ndp: # plusinvnat3b_inf print('Assuming that the suffix "_inf" in %r means that this will not converge' % (id_ndp)) print('Skipping this test') return try: ndp.check_fully_connected() except NotConnected: print('Skipping test_conversion because %r not connected.' % id_ndp) return dp = ndp.get_dp() F = dp.get_fun_space() R = dp.get_res_space() fs = F.get_minimal_elements() max_elements = 5 if len(fs) >= max_elements: fs = list(fs)[:max_elements] UR = UpperSets(R) for f in fs: try: res = dp.solve(f) print('%s -> %s' % (F.format(f), UR.format(res))) for r in res.minimals: imps = dp.get_implementations_f_r(f, r) print(imps) except NotSolvableNeedsApprox: break
def check_power8(): # TODO: move to ther files ndp = parse_ndp(""" mcdp { requires a [dimensionless] requires b [dimensionless] provides c [dimensionless] a + b >= c } """) dp = ndp.get_dp() print(dp.repr_long()) nl = 5 nu = 5 dpL, dpU = get_dp_bounds(dp, nl, nu) print(dpL.repr_long()) print(dpU.repr_long()) f = 10.0 UR = UpperSets(dp.get_res_space()) Rl = dpL.solve(f) Ru = dpU.solve(f) assert_equal(len(Rl.minimals), nl) assert_equal(len(Ru.minimals), nu) print('Rl: %s' % UR.format(Rl)) print('Ru: %s' % UR.format(Ru)) UR.check_leq(Rl, Ru) import numpy as np for x in np.linspace(0, f, 100): y = f - x p = (x, y) Rl.belongs(p)
def solve_stats(ndp, n, algo): res = {} query = { "travel_distance": " 2 km", "carry_payload": "100 g", "num_missions": "100 []", } context = Context() f = convert_string_query(ndp=ndp, query=query, context=context) dp0 = ndp.get_dp() dpL, dpU = get_dp_bounds(dp0, nl=n, nu=n) F = dp0.get_fun_space() F.belongs(f) logger = None InvMult2.ALGO = algo traceL = Tracer(logger=logger) resL = dpL.solve_trace(f, traceL) traceU = Tracer(logger=logger) resU = dpU.solve_trace(f, traceU) R = dp0.get_res_space() UR = UpperSets(R) print('resultsL: %s' % UR.format(resL)) print('resultsU: %s' % UR.format(resU)) res['traceL'] = traceL res['traceU'] = traceU res['resL'] = resL res['resU'] = resU res['n'] = n res['query'] = query return res
def solve_stats(ndp): res = {} query = { "endurance": "1.5 hour", "velocity": "1 m/s", "extra_power": " 1 W", "extra_payload": "100 g", "num_missions": "100 []", } context = Context() f = convert_string_query(ndp=ndp, query=query, context=context) dp0 = ndp.get_dp() dpL, dpU = get_dp_bounds(dp0, nl=1, nu=1) F = dp0.get_fun_space() F.belongs(f) from mocdp import logger traceL = Tracer(logger=logger) resL = dpL.solve_trace(f, traceL) traceU = Tracer(logger=logger) resU = dpU.solve_trace(f, traceU) R = dp0.get_res_space() UR = UpperSets(R) print('resultsL: %s' % UR.format(resL)) print('resultsU: %s' % UR.format(resU)) res['traceL'] = traceL res['traceU'] = traceU res['resL'] = resL res['resU'] = resU res['nsteps'] = 100 return res
def dual01_chain(id_dp, dp): try: with primitive_dp_test(id_dp, dp): print('Starting testing with %r' % id_dp) # get a chain of resources F = dp.get_fun_space() R = dp.get_res_space() # try to solve try: dp.solve(F.witness()) dp.solve_r(R.witness()) except NotSolvableNeedsApprox: print('NotSolvableNeedsApprox - doing lower bound ') n = 5 dpL, dpU = get_dp_bounds(dp, nl=n, nu=n) dual01_chain(id_dp+'_L%s'%n, dpL) dual01_chain(id_dp+'_U%s'%n, dpU) return LF = LowerSets(F) UR = UpperSets(R) rchain = R.get_test_chain(n=8) poset_check_chain(R, rchain) try: lfchain = list(map(dp.solve_r, rchain)) for lf in lfchain: LF.belongs(lf) except NotSolvableNeedsApprox as e: print('skipping because %s' % e) return try: poset_check_chain(LF, list(reversed(lfchain))) except ValueError as e: msg = 'The results of solve_r() are not a chain.' raise_wrapped(Exception, e, msg, chain=rchain, lfchain=lfchain) # now, for each functionality f, # we know that the corresponding resource should be feasible for lf, r in zip(lfchain, rchain): print('') print('r: %s' % R.format(r)) print('lf = h*(r) = %s' % LF.format(lf)) for f in lf.maximals: print(' f = %s' % F.format(f)) f_ur = dp.solve(f) print(' f_ur = h(f) = %s' % UR.format(f_ur)) try: f_ur.belongs(r) except NotBelongs as e: try: Rcomp.tolerate_numerical_errors = True f_ur.belongs(r) logger.info('In this case, there was a numerical error') logger.info('Rcomp.tolerate_numerical_errors = True solved the problem') except: msg = '' raise_wrapped(AssertionError, e, msg, lf=lf, r=r, f_ur=f_ur, r_repr=r.__repr__(), f_ur_minimals=f_ur.minimals.__repr__()) finally: Rcomp.tolerate_numerical_errors = False
def friendly_solve(ndp, query, result_like='dict(str:str)', upper=None, lower=None): """ query = dict(power=(100,"W")) result_like = dict(power="W") s = solve """ #print('friendly_solve(upper=%s, lower=%s)' % (upper, lower)) # TODO: replace with convert_string_query(ndp, query, context): fnames = ndp.get_fnames() rnames = ndp.get_rnames() if not len(rnames) >= 1: raise NotImplementedError() value = [] for fname in fnames: if not fname in query: msg = 'Missing function' raise_desc(ValueError, msg, fname=fname, query=query, fnames=fnames) F = ndp.get_ftype(fname) q, qs = query[fname] s = '%s %s' % (q, qs) try: val = interpret_params_1string(s, F=F) except NotLeq as e: raise_wrapped(ValueError, e, 'wrong type', fname=fname) value.append(val) if len(fnames) == 1: value = value[0] else: value = tuple(value) if hasattr(ndp, '_cache_dp0'): dp0 = ndp._cache_dp0 else: dp0 = ndp.get_dp() ndp._cache_dp0 = dp0 if upper is not None: _, dp = get_dp_bounds(dp0, nl=1, nu=upper) elif lower is not None: dp, _ = get_dp_bounds(dp0, nl=lower, nu=1) else: dp = dp0 F = dp.get_fun_space() F.belongs(value) from mcdp import logger trace = Tracer(logger=logger) res = dp.solve_trace(value, trace) R = dp.get_res_space() UR = UpperSets(R) print('value: %s' % F.format(value)) print('results: %s' % UR.format(res)) ares = [] implementations = [] for r in res.minimals: rnames = ndp.get_rnames() fr = dict() for rname, sunit in result_like.items(): if not rname in rnames: msg = 'Could not find resource %r.' % rname raise_desc(ValueError, msg, rnames=rnames) i = rnames.index(rname) unit = interpret_string_as_space(sunit) Ri = ndp.get_rtype(rname) if len(rnames) > 1: ri = r[i] else: assert i == 0 ri = r v = express_value_in_isomorphic_space(S1=Ri, s1=ri, S2=unit) fr[rname] = v ares.append(fr) ms = dp.get_implementations_f_r(value, r) implementations.append(ms) return ares, implementations
def dual01_chain(id_dp, dp): try: with primitive_dp_test(id_dp, dp): print('Starting testing with %r' % id_dp) # get a chain of resources F = dp.get_fun_space() R = dp.get_res_space() # try to solve try: dp.solve(F.witness()) dp.solve_r(R.witness()) except NotSolvableNeedsApprox: print('NotSolvableNeedsApprox - doing lower bound ') n = 5 dpL, dpU = get_dp_bounds(dp, nl=n, nu=n) dual01_chain(id_dp+'_L%s'%n, dpL) dual01_chain(id_dp+'_U%s'%n, dpU) return LF = LowerSets(F) UR = UpperSets(R) rchain = R.get_test_chain(n=8) poset_check_chain(R, rchain) try: lfchain = list(map(dp.solve_r, rchain)) for lf in lfchain: LF.belongs(lf) except NotSolvableNeedsApprox as e: print('skipping because %s' % e) return try: poset_check_chain(LF, list(reversed(lfchain))) except ValueError as e: msg = 'The results of solve_r() are not a chain.' raise_wrapped(Exception, e, msg, chain=rchain, lfchain=lfchain) # now, for each functionality f, # we know that the corresponding resource should be feasible for lf, r in zip(lfchain, rchain): print('') print('r: %s' % R.format(r)) print('lf = h*(r) = %s' % LF.format(lf)) for f in lf.maximals: print(' f = %s' % F.format(f)) f_ur = dp.solve(f) print(' f_ur = h(f) = %s' % UR.format(f_ur)) try: f_ur.belongs(r) except NotBelongs as e: try: Rcomp.tolerate_numerical_errors = True f_ur.belongs(r) logger.info('In this case, there was a numerical error') logger.info('Rcomp.tolerate_numerical_errors = True solved the problem') except: msg = '' raise_wrapped(AssertionError, e, msg, lf=lf, r=r, f_ur=f_ur, r_repr=r.__repr__(), f_ur_minimals=f_ur.minimals.__repr__()) finally: Rcomp.tolerate_numerical_errors = False
def process_ftor(self, e, string, do_approximations, nl, nu): mcdp_library = library_from_env(e) parsed = mcdp_library.parse_constant(string) space = parsed.unit value = parsed.value ndp, dp = self.get_ndp_dp_e(e) F = dp.get_fun_space() UR = UpperSets(dp.get_res_space()) try: f = parsed.cast_value(F) except NotLeq: msg = 'Space %s cannot be converted to %s' % (parsed.unit, F) raise DPSemanticError(msg) logger.info('query rtof: %s ...' % F.format(f)) tracer = Tracer(logger=logger) intervals = False max_steps = 10000 res = {} if do_approximations: dpl, dpu = get_dp_bounds(dp, nl, nu) result_l, _trace = solve_meat_solve_ftor(tracer, ndp, dpl, f, intervals, max_steps, False) result_u, trace = solve_meat_solve_ftor(tracer, ndp, dpu, f, intervals, max_steps, False) data = dict(result_l=result_l, result_u=result_u, dpl=dpl, dpu=dpu) res['output_result'] = 'Lower: %s\nUpper: %s' % ( UR.format(result_l), UR.format(result_u)) else: try: result, trace = solve_meat_solve_ftor(tracer, ndp, dp, f, intervals, max_steps, False) except NotSolvableNeedsApprox: msg = 'The design problem has infinite antichains. Please use approximations.' raise NeedsApprox(msg) data = dict(result=result, dp=dp) res['output_result'] = UR.format(result) e = cgi.escape res['output_space'] = e(space.__repr__() + '\n' + str(type(space))) res['output_raw'] = e(value.__repr__() + '\n' + str(type(value))) res['output_formatted'] = e(space.format(value)) res['output_trace'] = str(trace) return data, res
def friendly_solve(ndp, query, result_like='dict(str:str)', upper=None, lower=None): """ query = dict(power=(100,"W")) result_like = dict(power="W") s = solve """ #print('friendly_solve(upper=%s, lower=%s)' % (upper, lower)) # TODO: replace with convert_string_query(ndp, query, context): fnames = ndp.get_fnames() rnames = ndp.get_rnames() if not len(rnames) >= 1: raise NotImplementedError() value = [] for fname in fnames: if not fname in query: msg = 'Missing function' raise_desc(ValueError, msg, fname=fname, query=query, fnames=fnames) F = ndp.get_ftype(fname) q, qs = query[fname] s = '%s %s' % (q, qs) try: val = interpret_params_1string(s, F=F) except NotLeq as e: raise_wrapped(ValueError, e, 'wrong type', fname=fname) value.append(val) if len(fnames) == 1: value = value[0] else: value = tuple(value) if hasattr(ndp, '_cache_dp0'): dp0 = ndp._cache_dp0 else: dp0 = ndp.get_dp() ndp._cache_dp0 = dp0 if upper is not None: _, dp = get_dp_bounds(dp0, nl=1, nu=upper) elif lower is not None: dp, _ = get_dp_bounds(dp0, nl=lower, nu=1) else: dp = dp0 F = dp.get_fun_space() F.belongs(value) from mocdp import logger trace = Tracer(logger=logger) res = dp.solve_trace(value, trace) R = dp.get_res_space() UR = UpperSets(R) print('value: %s' % F.format(value)) print('results: %s' % UR.format(res)) ares = [] implementations = [] for r in res.minimals: rnames = ndp.get_rnames() fr = dict() for rname, sunit in result_like.items(): if not rname in rnames: msg = 'Could not find resource %r.' % rname raise_desc(ValueError, msg, rnames=rnames) i = rnames.index(rname) unit = interpret_string_as_space(sunit) Ri = ndp.get_rtype(rname) if len(rnames) > 1: ri = r[i] else: assert i == 0 ri = r v = express_value_in_isomorphic_space(S1=Ri, s1=ri, S2=unit) fr[rname] = v ares.append(fr) ms = dp.get_implementations_f_r(value, r) implementations.append(ms) return ares, implementations