Пример #1
0
int infogap_obs( struct opt_data *op )
{
	int i, j, ig_index, status, success = 0, count, neval_total, njac_total, no_memory = 0;
	double *opt_params, phi_min = HUGE_VAL;
	int ( *optimize_func )( struct opt_data * op );
	if( ( opt_params = ( double * ) malloc( op->pd->nOptParam * sizeof( double ) ) ) == NULL ) no_memory = 1;
	if( no_memory ) { tprintf( "Not enough memory!\n" ); return( 0 ); }
	tprintf( "\n\nInfo-gap analysis: observation step %g observation domain %g\nInfo-gap search: ", op->cd->obsstep, op->cd->obsdomain );
	if( op->cd->obsstep > DBL_EPSILON ) tprintf( "maximum\n" ); else tprintf( "minimum\n" );
	tprintf( "Number of predictions %d\n", op->preds->nTObs );
	for( i = 0; i < op->preds->nTObs; i++ )
	{
		// op->preds->obs_best are updated in mads_func.c
		if( op->cd->obsstep > DBL_EPSILON ) op->preds->obs_best[i] = -HUGE_VAL; // max search
		else op->preds->obs_best[i] = HUGE_VAL; // min search
		j = op->preds->obs_index[i];
		op->od->obs_weight[j] *= -1;
	}
	ig_index = op->preds->obs_index[0]; // first prediction is applied only
	tprintf( "Info-gap observation:\n" );
	tprintf( "%-20s: info-gap target %12g weight %12g range %12g - %12g\n", op->od->obs_id[ig_index], op->od->obs_target[ig_index], op->od->obs_weight[ig_index], op->od->obs_min[ig_index], op->od->obs_max[ig_index] );
	if( op->cd->obsstep > DBL_EPSILON ) { op->od->obs_target[ig_index] = op->od->obs_min[ig_index]; op->od->obs_min[ig_index] -= op->cd->obsstep / 2; } // obsstep is positive
	else { op->od->obs_target[ig_index] = op->od->obs_max[ig_index]; op->od->obs_max[ig_index] -= op->cd->obsstep / 2; } // obsstep is negative
	if( strncasecmp( op->cd->opt_method, "lm", 2 ) == 0 ) optimize_func = optimize_lm; // Define optimization method: LM
	else optimize_func = optimize_pso; // Define optimization method: PSO
	neval_total = njac_total = count = 0;
	while( 1 )
	{
		tprintf( "\nInfo-gap analysis #%d\n", ++count );
		tprintf( "%-20s: info-gap target %12g weight %12g range %12g - %12g\n", op->od->obs_id[ig_index], op->od->obs_target[ig_index], op->od->obs_weight[ig_index], op->od->obs_min[ig_index], op->od->obs_max[ig_index] );
		op->cd->neval = op->cd->njac = 0;
		if( op->cd->analysis_type == IGRND ) status = igrnd( op );
		else status = optimize_func( op );
		neval_total += op->cd->neval;
		njac_total += op->cd->njac;
		if( !status ) break;
		if( op->success )
		{
			for( i = 0; i < op->pd->nOptParam; i++ ) opt_params[i] = op->pd->var[op->pd->var_index[i]];
			for( i = 0; i < op->od->nTObs; i++ ) op->od->obs_best[i] = op->od->obs_current[i];
			phi_min = op->phi;
			success = 1;
		}
		tprintf( "Intermediate info-gap results for model predictions:\n" );
		tprintf( "%-20s: info-gap target %12g weight %12g range %12g - %12g\n", op->od->obs_id[ig_index], op->od->obs_target[ig_index], op->od->obs_weight[ig_index], op->od->obs_min[ig_index], op->od->obs_max[ig_index] );
		for( i = 0; i < op->preds->nTObs; i++ )
		{
			j = op->preds->obs_index[i];
			if( op->cd->obsstep > DBL_EPSILON ) tprintf( "%-20s: Current info-gap max %12g Observation step %g Observation domain %g Success %d\n", op->od->obs_id[j], op->preds->obs_best[i], op->cd->obsstep, op->cd->obsdomain, op->success );
			else                           tprintf( "%-20s: Current info-gap min %12g Observation step %g Observation domain %g Success %d\n", op->od->obs_id[j], op->preds->obs_best[i], op->cd->obsstep, op->cd->obsdomain, op->success );
		}
		if( !op->success ) break;
		if( op->cd->debug ) print_results( op, 1 );
		save_results( 1, "infogap", op, op->gd );
		op->od->obs_target[ig_index] += op->cd->obsstep;
		if( op->cd->obsstep > DBL_EPSILON ) // max search
		{
			if( op->od->obs_target[ig_index] > op->od->obs_max[ig_index] ) break;
			if( fabs( op->preds->obs_best[0] - op->od->obs_max[ig_index] ) < DBL_EPSILON ) break;
			op->od->obs_min[ig_index] += op->cd->obsstep;
			j = ( int )( ( double )( op->preds->obs_best[0] - op->od->obs_min[ig_index] + op->cd->obsstep / 2 ) / op->cd->obsstep + 1 );
			op->od->obs_target[ig_index] += op->cd->obsstep * j;
			op->od->obs_min[ig_index] += op->cd->obsstep * j;
			if( op->od->obs_target[ig_index] > op->od->obs_max[ig_index] ) op->od->obs_target[ig_index] = op->od->obs_max[ig_index];
			if( op->od->obs_min[ig_index] > op->od->obs_max[ig_index] ) op->od->obs_min[ig_index] = op->od->obs_max[ig_index];
		}
		else // min search
		{
			if( op->od->obs_target[ig_index] < op->od->obs_min[ig_index] ) break;
			if( fabs( op->preds->obs_best[0] - op->od->obs_min[ig_index] ) < DBL_EPSILON ) break;
			op->od->obs_max[ig_index] += op->cd->obsstep; // obsstep is negative
			j = ( int )( ( double )( op->od->obs_max[ig_index] - op->preds->obs_best[0] - op->cd->obsstep / 2 ) / -op->cd->obsstep + 1 ); // obsstep is negative
			op->od->obs_target[ig_index] += op->cd->obsstep * j;
			op->od->obs_max[ig_index] += op->cd->obsstep * j;
			if( op->od->obs_target[ig_index] < op->od->obs_min[ig_index] ) op->od->obs_target[ig_index] = op->od->obs_min[ig_index];
			if( op->od->obs_max[ig_index] < op->od->obs_min[ig_index] ) op->od->obs_max[ig_index] = op->od->obs_min[ig_index];
		}
	}
	op->cd->neval = neval_total; // provide the correct number of total evaluations
	op->cd->njac = njac_total; // provide the correct number of total evaluations
	if( success )
	{
		for( i = 0; i < op->pd->nOptParam; i++ ) op->cd->var[i] = op->pd->var[op->pd->var_index[i]] = op->pd->var_current[i] = op->pd->var_best[i] = opt_params[i];
		for( i = 0; i < op->od->nTObs; i++ ) op->od->obs_current[i] = op->od->obs_best[i];
		op->phi = phi_min;
		op->success = success;
	}
	else tprintf( "\nWARNING: Info-gap analysis failed to find acceptable solutions!\n" );
	tprintf( "\nInfo-gap results for model predictions:\n" );
	for( i = 0; i < op->preds->nTObs; i++ )
	{
		j = op->preds->obs_index[i];
		if( op->cd->obsstep > DBL_EPSILON ) tprintf( "%-20s: Info-gap max %12g Observation step %g Observation domain %g\n", op->od->obs_id[j], op->preds->obs_best[i], op->cd->obsstep, op->cd->obsdomain ); // max search
		else                           tprintf( "%-20s: Info-gap min %12g Observation step %g Observation domain %g\n", op->od->obs_id[j], op->preds->obs_best[i], op->cd->obsstep, op->cd->obsdomain ); // min search
		op->od->obs_target[j] = op->preds->obs_target[i];
		op->od->obs_min[j] = op->preds->obs_min[i];
		op->od->obs_max[j] = op->preds->obs_max[i];
		op->od->obs_weight[j] *= -1;
	}
	tprintf( "\n" );
	free( opt_params );
	print_results( op, 1 );
	save_results( 1, "", op, op->gd );
	return( 1 );
}
Пример #2
0
void optimize(Index& index, php::Program& program) {
    assert(check(program));
    trace_time tracer("optimize");
    SCOPE_EXIT { state_after("optimize", program); };

    // Counters, just for debug printing.
    std::atomic<uint32_t> total_funcs{0};
    auto round = uint32_t{0};

    /*
     * Algorithm:
     *
     * Start by running an analyze pass on every function.  During
     * analysis, information about functions or classes will be
     * requested from the Index, which initially won't really know much,
     * but will record a dependency.  This part is done in parallel: no
     * passes are mutating anything, just reading from the Index.
     *
     * After a pass, we do a single-threaded "update" step to prepare
     * for the next pass: for each function that was analyzed, note the
     * facts we learned that may aid analyzing other functions in the
     * program, and register them in the index.  At this point, if any
     * of these facts are more useful than they used to be, add all the
     * Contexts that had a dependency on the new information to the work
     * list again, in case they can do better based on the new fact.
     *
     * Repeat until the work list is empty.
     */
    auto work = initial_work(program);
    while (!work.empty()) {
        auto const results = [&] {
            trace_time trace(
                "analyzing",
                folly::format("round {} -- {} work items", round, work.size()).str()
            );
            return parallel_map(
                work,
            [&] (const Context& ctx) -> folly::Optional<FuncAnalysis> {
                total_funcs.fetch_add(1, std::memory_order_relaxed);
                return analyze_func(index, ctx);
            }
            );
        }();
        work.clear();

        ++round;
        trace_time update_time("updating");

        std::set<Context> revisit;
        for (auto i = size_t{0}; i < results.size(); ++i) {
            auto& result = *results[i];

            assert(result.ctx.func == work[i].func);
            assert(result.ctx.cls == work[i].cls);
            assert(result.ctx.unit == work[i].unit);

            auto deps = index.refine_return_type(
                            result.ctx.func, result.inferredReturn
                        );
            for (auto& d : deps) revisit.insert(d);
        }

        std::copy(begin(revisit), end(revisit), std::back_inserter(work));
    }

    if (Trace::moduleEnabledRelease(Trace::hhbbc_time, 1)) {
        Trace::traceRelease("total function visits %u\n", total_funcs.load());
    }

    /*
     * Finally, use the results of all these iterations to perform
     * optimization.  This reanalyzes every function using our
     * now-very-updated Index, and then runs optimize_func with the
     * results.
     *
     * We do this in parallel: all the shared information is queried out
     * of the index, and each thread is allowed to modify the bytecode
     * for the function it is looking at.
     *
     * NOTE: currently they can't modify anything other than the
     * bytecode/Blocks, because other threads may be doing unlocked
     * queries to php::Func and php::Class structures.
     */
    trace_time final_pass("final pass");
    work = initial_work(program);
    parallel_for_each(
        initial_work(program),
    [&] (Context ctx) {
        optimize_func(index, analyze_func(index, ctx));
    }
    );
}