示例#1
0
def evaluate_contract_in_series(
        contract_valuation_id, contract_valuation_repo, market_simulation_repo,
        simulated_price_repo, call_requirement_repo, call_dependencies_repo,
        call_link_repo, call_result_repo, perturbation_dependencies_repo,
        simulated_price_dependencies_repo, is_double_sided_deltas):
    """
    Computes value of contract by following the series execution order of its call dependency graph
    in directly evaluating each call in turn until the whole graph has been evaluated.
    """

    # Get the contract valuation entity (it knows which call dependency graph and which market simualation to use).
    contract_valuation = contract_valuation_repo[contract_valuation_id]
    assert isinstance(contract_valuation,
                      ContractValuation), contract_valuation

    # Get the contract specification ID.
    contract_specification_id = contract_valuation.contract_specification_id

    # Get the market simulation.
    market_simulation = market_simulation_repo[
        contract_valuation.market_simulation_id]

    # Follow the execution order...
    for call_id in regenerate_execution_order(contract_specification_id,
                                              call_link_repo):

        # Get the call requirement entity.
        call_requirement = call_requirement_repo[call_id]

        # Get the perturbation requirements for this call.
        perturbation_dependencies = perturbation_dependencies_repo[call_id]

        # Get the simulated price requirements for this call.
        simulation_requirements = simulated_price_dependencies_repo[
            call_id].requirements

        # Compute the call result.
        result_value, perturbed_values, involved_market_names = compute_call_result(
            contract_valuation=contract_valuation,
            call_requirement=call_requirement,
            market_simulation=market_simulation,
            perturbation_dependencies=perturbation_dependencies,
            call_dependencies_repo=call_dependencies_repo,
            call_result_repo=call_result_repo,
            simulated_price_repo=simulated_price_repo,
            simulation_requirements=simulation_requirements,
            is_double_sided_deltas=is_double_sided_deltas,
        )

        # Register the result.
        register_call_result(
            call_id=call_id,
            result_value=result_value,
            perturbed_values=perturbed_values,
            contract_valuation_id=contract_valuation_id,
            contract_specification_id=contract_specification_id,
            involved_market_names=involved_market_names)
def evaluate_contract_in_series(contract_valuation_id, contract_valuation_repo, market_simulation_repo,
                                simulated_price_repo, call_requirement_repo, call_dependencies_repo,
                                call_link_repo, call_result_repo, perturbation_dependencies_repo,
                                simulated_price_dependencies_repo, is_double_sided_deltas):
    """
    Computes value of contract by following the series execution order of its call dependency graph
    in directly evaluating each call in turn until the whole graph has been evaluated.
    """

    # Get the contract valuation entity (it knows which call dependency graph and which market simualation to use).
    contract_valuation = contract_valuation_repo[contract_valuation_id]
    assert isinstance(contract_valuation, ContractValuation), contract_valuation

    # Get the contract specification ID.
    contract_specification_id = contract_valuation.contract_specification_id

    # Get the market simulation.
    market_simulation = market_simulation_repo[contract_valuation.market_simulation_id]

    # Follow the execution order...
    for call_id in regenerate_execution_order(contract_specification_id, call_link_repo):

        # Get the call requirement entity.
        call_requirement = call_requirement_repo[call_id]

        # Get the perturbation requirements for this call.
        perturbation_dependencies = perturbation_dependencies_repo[call_id]

        # Get the simulated price requirements for this call.
        simulation_requirements = simulated_price_dependencies_repo[call_id].requirements

        # Compute the call result.
        result_value, perturbed_values, involved_market_names = compute_call_result(
            contract_valuation=contract_valuation,
            call_requirement=call_requirement,
            market_simulation=market_simulation,
            perturbation_dependencies=perturbation_dependencies,
            call_dependencies_repo=call_dependencies_repo,
            call_result_repo=call_result_repo,
            simulated_price_repo=simulated_price_repo,
            simulation_requirements=simulation_requirements,
            is_double_sided_deltas=is_double_sided_deltas,
        )

        # Register the result.
        register_call_result(
            call_id=call_id,
            result_value=result_value,
            perturbed_values=perturbed_values,
            contract_valuation_id=contract_valuation_id,
            contract_specification_id=contract_specification_id,
            involved_market_names=involved_market_names
        )
    def test_delete_result(self):
        # In this test, there are two "calls": call1 and call2.
        # It is supposed that call1 happens first, and call2 uses the result of call1.
        # Therefore call2 depends upon call1, call1 is a dependency of call2, and call2 is a dependent of call1.
        call1_id = 'call1'
        call2_id = 'call2'
        contract_valuation_id = 'val1'
        contract_specification_id = 'spec1'
        # call1_id = uuid4().hex
        # call2_id = uuid4().hex
        # contract_valuation_id = uuid4().hex
        # contract_specification_id = uuid4().hex

        register_call_dependencies(call2_id, [call1_id])

        # Check the policy has the dependencies for call2.
        self.assertEqual(self.policy.dependencies[call2_id], [call1_id])

        # Register dependents of call1, as call2.
        register_call_dependents(call1_id, [call2_id])

        # Check the policy has the dependencies for call2.
        self.assertEqual(self.policy.dependents[call1_id], [call2_id])

        # Register call result for call1.
        # - this should trigger deletion of call2 result
        call1_result = register_call_result(call1_id, 1.0, {}, contract_valuation_id, contract_specification_id, [])

        # Check the policy has the result for call1.
        self.assertTrue(call1_result.id in self.policy.result)

        # Check the result for call1 exists.
        self.assertTrue(call1_result.id in self.call_result_repo)

        # Register call result for call2.
        call2_result = register_call_result(call2_id, 1.0, {}, contract_valuation_id, contract_specification_id, [])

        # Check the policy has the result for call2.
        self.assertTrue(call2_result.id in self.policy.result)

        # Check the result for call2 exists.
        self.assertTrue(call2_result.id in self.call_result_repo)

        # Check the policy does not have the result for call1.
        self.assertFalse(call1_result.id in self.policy.result)

        # Check the result for call1 doesn't exist (because it's dependents have results).
        self.assertFalse(call1_result.id in self.call_result_repo)
    def test_register_call_result(self):
        contract_specification_id = create_uuid4()
        contract_valuation_id = create_uuid4()
        call_id = create_uuid4()

        call_result_id = make_call_result_id(contract_valuation_id, call_id)
        self.assertRaises(KeyError, self.app.call_result_repo.__getitem__, call_result_id)

        register_call_result(call_id=call_id, result_value=123, perturbed_values={},
                             contract_valuation_id=contract_valuation_id,
                             contract_specification_id=contract_specification_id,
                             involved_market_names=[])

        call_result = self.app.call_result_repo[call_result_id]
        assert isinstance(call_result, CallResult)
        self.assertEqual(call_result.result_value, 123)
    def test_register_call_result(self):
        dependency_graph_id = create_uuid4()
        contract_valuation_id = create_uuid4()
        call_id = create_uuid4()

        call_result_id = make_call_result_id(contract_valuation_id, call_id)
        self.assertRaises(KeyError, self.app.call_result_repo.__getitem__,
                          call_result_id)

        register_call_result(call_id=call_id,
                             result_value=123,
                             perturbed_values={},
                             contract_valuation_id=contract_valuation_id,
                             dependency_graph_id=dependency_graph_id)

        call_result = self.app.call_result_repo[call_result_id]
        assert isinstance(call_result, CallResult)
        self.assertEqual(call_result.result_value, 123)
示例#6
0
def evaluate_call_and_queue_next_calls(
        contract_valuation_id, contract_specification_id, call_id,
        contract_valuation_repo, call_requirement_repo, market_simulation_repo,
        call_dependencies_repo, call_result_repo, simulated_price_repo,
        perturbation_dependencies_repo, simulated_price_requirements_repo):
    # Get the contract valuation.
    contract_valuation = contract_valuation_repo[contract_valuation_id]
    assert isinstance(contract_valuation, ContractValuation)

    # Get the market simulation.
    market_simulation = market_simulation_repo[
        contract_valuation.market_simulation_id]

    # Get the call requirement.
    call_requirement = call_requirement_repo[call_id]

    # Get the perturbation dependencies for this call.
    perturbation_dependencies = perturbation_dependencies_repo[call_id]
    assert isinstance(perturbation_dependencies, PerturbationDependencies)

    # Get the simulated price requirements for this call.
    simulation_requirements = simulated_price_requirements_repo[
        call_id].requirements

    # Compute the call result.
    result_value, perturbed_values, involved_market_names = compute_call_result(
        contract_valuation=contract_valuation,
        call_requirement=call_requirement,
        market_simulation=market_simulation,
        perturbation_dependencies=perturbation_dependencies,
        call_dependencies_repo=call_dependencies_repo,
        call_result_repo=call_result_repo,
        simulated_price_repo=simulated_price_repo,
        simulation_requirements=simulation_requirements,
        is_double_sided_deltas=contract_valuation.is_double_sided_deltas,
    )

    # Register the call result.
    register_call_result(call_id=call_id,
                         result_value=result_value,
                         perturbed_values=perturbed_values,
                         contract_valuation_id=contract_valuation_id,
                         contract_specification_id=contract_specification_id,
                         involved_market_names=involved_market_names)
def evaluate_call_and_queue_next_calls(contract_valuation_id, contract_specification_id, call_id,
                                       contract_valuation_repo, call_requirement_repo, market_simulation_repo,
                                       call_dependencies_repo, call_result_repo, simulated_price_repo,
                                       perturbation_dependencies_repo, simulated_price_requirements_repo):
    # Get the contract valuation.
    contract_valuation = contract_valuation_repo[contract_valuation_id]
    assert isinstance(contract_valuation, ContractValuation)

    # Get the market simulation.
    market_simulation = market_simulation_repo[contract_valuation.market_simulation_id]

    # Get the call requirement.
    call_requirement = call_requirement_repo[call_id]

    # Get the perturbation dependencies for this call.
    perturbation_dependencies = perturbation_dependencies_repo[call_id]
    assert isinstance(perturbation_dependencies, PerturbationDependencies)

    # Get the simulated price requirements for this call.
    simulation_requirements = simulated_price_requirements_repo[call_id].requirements

    # Compute the call result.
    result_value, perturbed_values, involved_market_names = compute_call_result(
        contract_valuation=contract_valuation,
        call_requirement=call_requirement,
        market_simulation=market_simulation,
        perturbation_dependencies=perturbation_dependencies,
        call_dependencies_repo=call_dependencies_repo,
        call_result_repo=call_result_repo,
        simulated_price_repo=simulated_price_repo,
        simulation_requirements=simulation_requirements,
        is_double_sided_deltas=contract_valuation.is_double_sided_deltas,
    )

    # Register the call result.
    register_call_result(
        call_id=call_id,
        result_value=result_value,
        perturbed_values=perturbed_values,
        contract_valuation_id=contract_valuation_id,
        contract_specification_id=contract_specification_id,
        involved_market_names=involved_market_names
    )
示例#8
0
    def test_register_call_result(self):
        contract_specification_id = create_uuid4()
        contract_valuation_id = create_uuid4()
        call_id = create_uuid4()

        call_result_id = make_call_result_id(contract_valuation_id, call_id)
        self.assertRaises(KeyError, self.app.call_result_repo.__getitem__,
                          call_result_id)

        register_call_result(
            call_id=call_id,
            result_value=123,
            perturbed_values={},
            contract_valuation_id=contract_valuation_id,
            contract_specification_id=contract_specification_id,
            involved_market_names=[])

        call_result = self.app.call_result_repo[call_result_id]
        assert isinstance(call_result, CallResult)
        self.assertEqual(call_result.result_value, 123)
示例#9
0
    def generate_contract_valuation(self, dependency_graph_id, market_simulation):
        assert isinstance(dependency_graph_id, six.string_types), dependency_graph_id
        assert isinstance(market_simulation, MarketSimulation)
        v = self.register_contract_valuation(dependency_graph_id)

        for call_id in regenerate_execution_order(dependency_graph_id, self.call_link_repo):

            call = self.call_requirement_repo[call_id]
            assert isinstance(call, CallRequirement)

            # Evaluate the call requirement.
            dependency_values = get_dependency_values(call_id, self.call_dependencies_repo, self.call_result_repo)

            # - parse the expr
            stubbed_module = dsl_parse(call.dsl_source)

            assert isinstance(stubbed_module, Module), "Parsed stubbed expr string is not a module: %s" % stubbed_module

            # - build a namespace from the dependency values
            dsl_locals = DslNamespace(dependency_values)

            # - compile the parsed expr
            dsl_expr = stubbed_module.body[0].reduce(dsl_locals=dsl_locals, dsl_globals=DslNamespace())
            assert isinstance(dsl_expr, DslExpression), dsl_expr

            # - evaluate the compiled expr
            first_market_name = market_simulation.market_names[0] if market_simulation.market_names else None
            evaluation_kwds = {
                'simulated_price_repo': self.simulated_price_repo,
                'simulation_id': market_simulation.id,
                'interest_rate': market_simulation.interest_rate,
                'present_time': call.effective_present_time or market_simulation.observation_date,
                'first_market_name': first_market_name,
            }
            result_value = dsl_expr.evaluate(**evaluation_kwds)

            # - store the result
            register_call_result(call_id=call_id, result_value=result_value)
示例#10
0
def evaluate_call_and_queue_next_calls(contract_valuation_id,
                                       dependency_graph_id,
                                       call_id,
                                       call_evaluation_queue,
                                       contract_valuation_repo,
                                       call_requirement_repo,
                                       market_simulation_repo,
                                       call_dependencies_repo,
                                       call_result_repo,
                                       simulated_price_repo,
                                       call_dependents_repo,
                                       perturbation_dependencies_repo,
                                       simulated_price_requirements_repo,
                                       call_result_lock,
                                       compute_pool=None,
                                       result_counters=None,
                                       usage_counters=None):

    # Get the contract valuation.
    contract_valuation = contract_valuation_repo[contract_valuation_id]
    assert isinstance(contract_valuation, ContractValuation)

    # Get the market simulation.
    market_simulation = market_simulation_repo[
        contract_valuation.market_simulation_id]

    call_requirement = call_requirement_repo[call_id]

    perturbation_dependencies = perturbation_dependencies_repo[call_id]
    assert isinstance(perturbation_dependencies, PerturbationDependencies)

    # Get the simulated price requirements for this call.
    simulation_requirements = simulated_price_requirements_repo[
        call_id].requirements

    result_value, perturbed_values = compute_call_result(
        contract_valuation=contract_valuation,
        call_requirement=call_requirement,
        market_simulation=market_simulation,
        perturbation_dependencies=perturbation_dependencies,
        call_dependencies_repo=call_dependencies_repo,
        call_result_repo=call_result_repo,
        simulated_price_repo=simulated_price_repo,
        perturbation_dependencies_repo=perturbation_dependencies_repo,
        simulation_requirements=simulation_requirements,
        compute_pool=compute_pool,
    )

    # Lock the results.
    # - avoids race conditions when checking, after a result
    #   has been written, if all results are now available, whilst
    #   others are writing results.
    # - could perhaps do this with optimistic concurrency control, so
    #   that result events can be collected by dependents
    #   and then evaluated when all are received - to be robust against
    #   concurrent operations causing concurrency exceptions, an accumulating
    #   operation would require to be retried only as many times as there are
    #   remaining dependents.
    if call_result_lock is not None:
        call_result_lock.acquire()

    try:
        # Register this result.
        # Todo: Retries on concurrency errors.
        register_call_result(
            call_id=call_id,
            result_value=result_value,
            perturbed_values=perturbed_values,
            contract_valuation_id=contract_valuation_id,
            dependency_graph_id=dependency_graph_id,
        )

        # Find next calls.
        ready_generator = find_dependents_ready_to_be_evaluated(
            contract_valuation_id=contract_valuation_id,
            call_id=call_id,
            call_dependencies_repo=call_dependencies_repo,
            call_dependents_repo=call_dependents_repo,
            call_result_repo=call_result_repo,
            result_counters=result_counters,
        )

        # Check requirements, and discard result when dependency has been fully used.
        if usage_counters is not None:
            call_dependencies = call_dependencies_repo[call_id]
            assert isinstance(call_dependencies, CallDependencies)
            for dependency_id in call_dependencies.dependencies:
                dependency_result_id = make_call_result_id(
                    contract_valuation_id, dependency_id)
                try:
                    usage_counters[dependency_result_id].pop(
                    )  # Pop one off the array (atomic decrement).
                except (KeyError, IndexError):
                    call_result = call_result_repo[dependency_result_id]
                    # Todo: Maybe do discard operations after lock has been released?
                    call_result.discard()
                    # Need to remove from the cache if we are to save memory.
                    try:
                        del (call_result_repo._cache[dependency_result_id])
                    except:
                        pass

        if call_result_lock is not None:
            # Make a list from the generator, if we are locking results.
            next_call_ids = list(ready_generator)
        else:
            # Otherwise put things directly on the queue.
            next_call_ids = []
            for next_call_id in ready_generator:
                call_evaluation_queue.put(
                    (dependency_graph_id, contract_valuation_id, next_call_id))
                gevent.sleep(0)

    finally:
        # Unlock the results.
        if call_result_lock is not None:
            call_result_lock.release()

    # Queue the next calls (if there are any - see above).
    for next_call_id in next_call_ids:
        call_evaluation_queue.put(
            (dependency_graph_id, contract_valuation_id, next_call_id))
示例#11
0
 def register_call_result(self, call_id, result_value):
     return register_call_result(call_id=call_id, result_value=result_value)