! * \brief calc a complex expression involving two vars * * z = sum(e^(x/k) * sin(y^2 + (x + k*y)*sum(p, 1<=p<=k))/exp(0.3*k) , k >= 1) */
| 53 | * z = sum(e^(x/k) * sin(y^2 + (x + k*y)*sum(p, 1<=p<=k))/exp(0.3*k) , k >= 1) |
| 54 | */ |
| 55 | void test_two_var_coupled( |
| 56 | thin_function<SymbolVar(SymbolVar)> sym_exp, |
| 57 | thin_function<SymbolVar(SymbolVar)> sym_sin) { |
| 58 | set_rand_seed(19931102); |
| 59 | |
| 60 | constexpr float MAX_TERM_VAL = 1e-6, MAX_ERR = 1e-3; |
| 61 | |
| 62 | HostTensorGenerator<> gen; |
| 63 | auto host_x = gen({1}), host_y = gen({1}), host_loss_p = gen({1}); |
| 64 | |
| 65 | auto graph = ComputingGraph::make(); |
| 66 | auto x = opr::Host2DeviceCopy::make(*graph, host_x).rename("x"), |
| 67 | y = opr::Host2DeviceCopy::make(*graph, host_y).rename("y"), |
| 68 | loss_p = opr::Host2DeviceCopy::make(*graph, host_loss_p).rename("lp"); |
| 69 | |
| 70 | auto desc_maker = [&](opr::Loop::Desc& desc) { |
| 71 | auto t1_cup = desc.add_input_assignable(x + y), |
| 72 | t1_cdown = desc.add_input_assignable(x.make_scalar(1)), |
| 73 | k = desc.get_counter_var() + 1, |
| 74 | t0 = sym_exp(desc.add_input(x) / k).rename("t0"), |
| 75 | t1 = sym_sin(desc.add_input(y * y) + t1_cup / t1_cdown).rename("t1"), |
| 76 | term = (t0 * t1 / sym_exp(k * 0.3f)).rename("term"), |
| 77 | err_elem = (term * term > MAX_TERM_VAL * MAX_TERM_VAL).rename("err"), |
| 78 | result = desc.add_input_assignable(x.fill_retain_dtype(0)).rename("sum"), |
| 79 | result_next = result + term; |
| 80 | desc.assign(result, result_next); |
| 81 | desc.assign(t1_cup, t1_cup + desc.add_input(y)); |
| 82 | desc.assign(t1_cdown, t1_cdown + k + 1); |
| 83 | desc.set_loop_condition(opr::Dot::make(err_elem, err_elem)); |
| 84 | desc.add_output(result_next, OutputMode::LAST); |
| 85 | }; |
| 86 | |
| 87 | auto z = opr::Loop::make(desc_maker).at(0), loss = opr::Dot::make(z, loss_p), |
| 88 | gx = cg::grad(loss, x), gy = cg::grad(loss, y); |
| 89 | |
| 90 | HostTensorND host_z, host_gx, host_gy; |
| 91 | auto func = graph->compile( |
| 92 | {make_callback_copy(z, host_z), make_callback_copy(gx, host_gx), |
| 93 | make_callback_copy(gy, host_gy)}); |
| 94 | |
| 95 | for (size_t SIZE : {1, 23}) { |
| 96 | host_x->copy_from(*gen({SIZE})); |
| 97 | host_y->copy_from(*gen({SIZE})); |
| 98 | host_loss_p->copy_from(*gen({SIZE})); |
| 99 | auto px = host_x->ptr<float>(), py = host_y->ptr<float>(); |
| 100 | |
| 101 | func->execute(); |
| 102 | ASSERT_EQ(host_x->shape(), host_z.shape()); |
| 103 | ASSERT_EQ(host_x->shape(), host_gx.shape()); |
| 104 | ASSERT_EQ(host_x->shape(), host_gy.shape()); |
| 105 | auto pz = host_z.ptr<float>(), pgx = host_gx.ptr<float>(), |
| 106 | pgy = host_gy.ptr<float>(); |
| 107 | std::vector<float> vraw_z(SIZE), vraw_gx(SIZE), vraw_gy(SIZE); |
| 108 | |
| 109 | for (float k = 1;; k++) { |
| 110 | bool done = true; |
| 111 | for (size_t i = 0; i < SIZE; i++) { |
| 112 | auto x = px[i], y = py[i]; |
no test coverage detected