def test_checkpoint( tmp_path, exist_ok, with_name, with_info, single_checkpoint, step_attribs ): x = WithStep() fname = unique_name("abc", rand_digits=10, add_time=True, sep=".") try: file_name = x.checkpoint( path=tmp_path, file_name=fname if with_name else None, info={"r": 3} if with_info else None, exist_ok=exist_ok, single_checkpoint=single_checkpoint, step_attribs=step_attribs, ) assert ( file_name.name.split(".")[0].isnumeric() or single_checkpoint or all(_ in bad_attribs for _ in set(step_attribs)) or not any(hasattr(x, _) for _ in step_attribs) ) except ValueError as e: if "exist_ok" in str(e): assert not exist_ok else: raise e x = MyEntity() fname = unique_name("abc", rand_digits=10, add_time=True, sep=".") try: file_name = x.checkpoint( path=tmp_path, file_name=fname if with_name else None, info={"r": 3} if with_info else None, exist_ok=exist_ok, single_checkpoint=single_checkpoint, step_attribs=step_attribs, ) assert ( file_name.name.split(".")[0].isnumeric() or single_checkpoint or all(_ in bad_attribs for _ in set(step_attribs)) or not any(hasattr(x, _) for _ in step_attribs) ) except ValueError as e: if "exist_ok" in str(e): assert not exist_ok else: raise e
def test_nothing_happens_with_do_nothing(buy_missing, n_processes, initial_balance): world = generate_world( [DoNothingAgent], buy_missing_products=buy_missing, n_processes=n_processes, name=unique_name( f"scml2020tests/single/doing_nothing/" f"{'Buy' if buy_missing else 'Fine'}_p{n_processes}_b{initial_balance}", add_time=True, rand_digits=4, ), initial_balance=initial_balance, bankruptcy_limit=initial_balance, compact=COMPACT, no_logs=NOLOGS, ) world.run() assert len(world.contracts_per_step) == 0 for a, f, p in world.afp: if is_system_agent(a.id): continue if ( a.awi.my_input_product == 0 or a.awi.my_input_product == a.awi.n_processes - 1 ): assert f.current_balance <= initial_balance, ( f"{a.name} (process {a.awi.my_input_product} of {a.awi.n_processes})'s balance " f"should go down" )
def test_world_auto_checkpoint(tmp_path, single_checkpoint, checkpoint_every, exist_ok): import shutil new_folder: Path = tmp_path / unique_name("empty", sep="") new_folder.mkdir(parents=True, exist_ok=True) shutil.rmtree(new_folder) new_folder.mkdir(parents=True, exist_ok=True) filename = "mechanism" n_steps = 20 world = DummyWorld( n_steps=n_steps, checkpoint_every=checkpoint_every, checkpoint_folder=new_folder, checkpoint_filename=filename, extra_checkpoint_info=None, exist_ok=exist_ok, single_checkpoint=single_checkpoint, ) world.run() if 0 < checkpoint_every <= n_steps: if single_checkpoint: assert len(list(new_folder.glob("*"))) == 2, print( f"World ran for: {world.current_step}") else: assert len(list(new_folder.glob("*"))) >= 2 * (max( 1, world.current_step // checkpoint_every)) elif checkpoint_every > n_steps: assert len(list(new_folder.glob("*"))) == 2 else: assert len(list(new_folder.glob("*"))) == 0
def test_agents_go_bankrupt(n_processes): buy_missing = True world = generate_world( [RandomAgent], buy_missing_products=buy_missing, n_processes=n_processes, name=unique_name( f"scml2020tests/single/bankrupt/" f"{'Buy' if buy_missing else 'Fine'}_p{n_processes}", add_time=True, rand_digits=4, ), initial_balance=0, bankruptcy_limit=0, n_steps=10, compact=COMPACT, no_logs=NOLOGS, ) world.run() # assert len(world.signed_contracts) + len(world.cancelled_contracts) == 0 for a, f, p in world.afp: if is_system_agent(a.id): continue if ( a.awi.my_input_product == 0 or a.awi.my_input_product == a.awi.n_processes - 1 ): assert f.current_balance <= 0, ( f"{a.name} (process {a.awi.my_input_product} of {a.awi.n_processes})'s balance " f"should go down" ) assert f.is_bankrupt, ( f"{a.name} (process {a.awi.my_input_product} of {a.awi.n_processes}) should " f"be bankrupt (balance = {f.current_balance}, inventory={f.current_inventory})" )
def __init__(self, name: str = None) -> None: if name is not None: name = str(name) self.__uuid = (f'{name}-' if name is not None else "") + str( uuid.uuid4()) if name is None or len(name) == 0: name = unique_name('', add_time=False, rand_digits=16) self.__name = name super().__init__()
def test_is_nonzero_file(tmpdir): f_name = unique_name("") f = tmpdir / f_name assert is_nonzero_file(str(f)) is False with open(f, "w") as tst_file: tst_file.write("") assert is_nonzero_file(str(f)) is False with open(f, "w") as tst_file: tst_file.write("test") assert is_nonzero_file(str(f)) is True
def test_can_run_with_a_single_agent_type(agent_type, n_processes): world = generate_world( [agent_type], n_processes=n_processes, name=unique_name( f"scml2020tests/single/{agent_type.__name__}" f"Fine{n_processes}", add_time=True, rand_digits=4, ), compact=COMPACT, no_logs=NOLOGS, ) world.run() save_stats(world, world.log_folder)
def test_negotiator_ids_are_partner_ids(): n_processes = 5 world = generate_world( [MyOneShotAgent], n_processes=n_processes, name=unique_name( f"scml2020tests/single/{MyOneShotAgent.__name__}" f"Fine{n_processes}", add_time=True, rand_digits=4, ), compact=True, no_logs=True, ) world.run()
def test_ind_negotiators_genius(): n_processes = 5 world = generate_world( [MyGeniusIndNeg], n_processes=n_processes, name=unique_name( f"scml2020tests/single/{MyIndNeg.__name__}" f"Fine{n_processes}", add_time=True, rand_digits=4, ), compact=True, no_logs=True, ) world.run()
def test_something_happens_with_random_agents(n_processes): world = generate_world( [RandomOneShotAgent], n_processes=n_processes, name=unique_name( f"scml2020tests/single/do_something/" f"Fine_p{n_processes}", add_time=True, rand_digits=4, ), compact=COMPACT, no_logs=NOLOGS, n_steps=15, ) world.run() assert len(world.signed_contracts) + len(world.cancelled_contracts) != 0
def test_can_run_with_a_multiple_agent_types(agent_types, n_processes): world = generate_world( agent_types, name=unique_name( f"scml2020tests/multi/{'-'.join(_.__name__[:3] for _ in agent_types)}/" f"Fine_p{n_processes}", add_time=True, rand_digits=4, ), n_processes=n_processes, compact=COMPACT, no_logs=NOLOGS, ) world.run() save_stats(world, world.log_folder)
def test_can_run_with_a_multiple_agent_types(agent_types, buy_missing, n_processes): world = generate_world( agent_types, buy_missing_products=buy_missing, name=unique_name( f"scml2020tests/multi/{'-'.join(_.__name__[:3] for _ in agent_types)}/" f"{'Buy' if buy_missing else 'Fine'}_p{n_processes}", add_time=True, rand_digits=4, ), n_processes=n_processes, initial_balance=10_000, compact=COMPACT, no_logs=NOLOGS, ) world.run() save_stats(world, world.log_folder)
def test_auto_checkpoint(tmp_path, single_checkpoint, checkpoint_every, exist_ok): import shutil new_folder: Path = tmp_path / unique_name("empty", sep="") new_folder.mkdir(parents=True, exist_ok=True) shutil.rmtree(new_folder) new_folder.mkdir(parents=True, exist_ok=True) filename = "mechanism" n_outcomes, n_negotiators = 5, 3 n_steps = 50 mechanism = SAOMechanism( outcomes=n_outcomes, n_steps=n_steps, offering_is_accepting=True, avoid_ultimatum=False, checkpoint_every=checkpoint_every, checkpoint_folder=new_folder, checkpoint_filename=filename, extra_checkpoint_info=None, exist_ok=exist_ok, single_checkpoint=single_checkpoint, ) ufuns = MappingUtilityFunction.generate_random(n_negotiators, outcomes=n_outcomes) for i in range(n_negotiators): mechanism.add( AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[i], aspiration_type="conceder", ) mechanism.run() if 0 < checkpoint_every <= n_steps: if single_checkpoint: assert len(list(new_folder.glob("*"))) == 2 else: assert len(list(new_folder.glob("*"))) >= 2 * (max( 1, mechanism.state.step // checkpoint_every)) elif checkpoint_every > n_steps: assert len(list(new_folder.glob("*"))) == 2 else: assert len(list(new_folder.glob("*"))) == 0
def test_builtin_aspiration(): from negmas.helpers import get_full_type_name from scml.oneshot import SingleAgreementAspirationAgent n_processes = 2 world = generate_world( [SingleAgreementAspirationAgent], n_processes=n_processes, name=unique_name( f"scml2020tests/single/{SingleAgreementAspirationAgent.__name__}Fine{n_processes}", add_time=True, rand_digits=4, ), compact=True, no_logs=True, ) world.run()
def test_something_happens_with_random_agents(buy_missing, n_processes): world = generate_world( [RandomAgent], buy_missing_products=buy_missing, n_processes=n_processes, name=unique_name( f"scml2020tests/single/do_something/" f"{'Buy' if buy_missing else 'Fine'}_p{n_processes}", add_time=True, rand_digits=4, ), initial_balance=10_000, bankruptcy_limit=10_000, compact=COMPACT, no_logs=NOLOGS, n_steps=15, ) world.run() assert len(world.signed_contracts) + len(world.cancelled_contracts) != 0
def test_world_auto_checkpoint(tmp_path, single_checkpoint, checkpoint_every, exist_ok): import shutil new_folder: Path = tmp_path / unique_name("empty", sep="") new_folder.mkdir(parents=True, exist_ok=True) shutil.rmtree(new_folder) new_folder.mkdir(parents=True, exist_ok=True) filename = "scml" n_steps = 5 world = SCMLWorld.chain_world( log_file_name="", n_steps=n_steps, n_factories_per_level=1, consumer_kwargs={ "negotiator_type": "negmas.sao.NiceNegotiator", "consumption_horizon": 2, }, miner_kwargs={"negotiator_type": "negmas.sao.NiceNegotiator"}, checkpoint_every=checkpoint_every, checkpoint_folder=new_folder, checkpoint_filename=filename, extra_checkpoint_info=None, exist_ok=exist_ok, single_checkpoint=single_checkpoint, ) world.run() if 0 < checkpoint_every <= n_steps: if single_checkpoint: assert len(list(new_folder.glob("*"))) == 2, print( f"SCML2020World ran for: {world.current_step}" ) else: assert len(list(new_folder.glob("*"))) >= 2 * ( max(1, world.current_step // checkpoint_every) ) elif checkpoint_every > n_steps: assert len(list(new_folder.glob("*"))) == 2 else: assert len(list(new_folder.glob("*"))) == 0
def anac2020_config_generator( n_competitors: int, n_agents_per_competitor: int, agent_names_reveal_type: bool = False, non_competitors: Optional[Tuple[Union[str, SCML2020Agent]]] = None, non_competitor_params: Optional[Tuple[Dict[str, Any]]] = None, compact: bool = True, *, n_steps: Union[int, Tuple[int, int]] = (50, 100), n_processes: Tuple[int, int] = (2, 5), min_factories_per_level: int = 2, # strictly guaranteed max_factories_per_level: int = 6, # not strictly guaranteed n_lines: int = 10, **kwargs, ) -> List[Dict[str, Any]]: if non_competitors is None: non_competitors = tuple(DefaultAgent) if isinstance(n_processes, Iterable): n_processes = tuple(n_processes) else: n_processes = [n_processes, n_processes] n_steps = _intin(n_steps) n_processes = randint(*n_processes) n_agents = n_agents_per_competitor * n_competitors n_default_managers = ( min( n_processes * max_factories_per_level, max(0, n_processes * min_factories_per_level), ) - n_agents ) n_defaults = integer_cut(n_default_managers, n_processes, 0) n_a_list = integer_cut(n_agents, n_processes, 0) for i, n_a in enumerate(n_a_list): if n_a + n_defaults[i] < min_factories_per_level: n_defaults[i] = min_factories_per_level - n_a if n_a + n_defaults[i] > max_factories_per_level and n_defaults[i] > 1: n_defaults[i] = max(1, min_factories_per_level - n_a) n_f_list = [a + b for a, b in zip(n_defaults, n_a_list)] n_factories = sum(n_f_list) if non_competitor_params is None: non_competitor_params = [{}] * len(non_competitors) non_competitors = [get_full_type_name(_) for _ in non_competitors] max_def_agents = len(non_competitors) - 1 agent_types = [None] * n_factories manager_params = [None] * n_factories first_in_level = 0 for level in range(n_processes): n_d = n_defaults[level] n_f = n_f_list[level] assert ( n_d <= n_f ), f"Got {n_f} total factories at level {level} out of which {n_d} are default!!" for j in range(n_f): if j >= n_f - n_d: # default managers are last managers in the list def_indx = randint(0, max_def_agents) agent_types[first_in_level + j] = non_competitors[def_indx] params_ = copy.deepcopy(non_competitor_params[def_indx]) if agent_names_reveal_type: params_["name"] = f"_df_{level}_{j}" else: params_[ "name" ] = ( f"_df_{level}_{j}" ) # because I use name to know that this is a default agent in evaluate. # @todo do not use name to identify default agents in evaluation manager_params[first_in_level + j] = params_ first_in_level += n_f world_name = unique_name("", add_time=True, rand_digits=4) agent_types = [ get_full_type_name(_) if isinstance(_, SCML2020Agent) else _ for _ in agent_types ] world_params = dict( name=world_name, agent_types=agent_types, time_limit=7200 + 3600, neg_time_limit=120, neg_n_steps=20, neg_step_time_limit=10, negotiation_speed=21, breach_penalty=0.2, interest_rate=0.08, bankruptcy_limit=1.0, initial_balance=None, start_negotiations_immediately=False, n_agents_per_process=n_f_list, n_processes=n_processes, n_steps=n_steps, n_lines=n_lines, compact=compact, ) world_params.update(kwargs) config = { "world_params": world_params, "compact": compact, "scoring_context": {}, "non_competitors": non_competitors, "non_competitor_params": non_competitor_params, "agent_types": agent_types, "agent_params": manager_params, } config.update(kwargs) return [config]
def test_can_run_from_checkpoint(tmp_path, single_checkpoint, checkpoint_every, exist_ok): import shutil new_folder: Path = tmp_path / unique_name("empty", sep="") second_folder: Path = tmp_path / unique_name("second", sep="") new_folder.mkdir(parents=True, exist_ok=True) shutil.rmtree(new_folder) new_folder.mkdir(parents=True, exist_ok=True) filename = "mechanism" second_folder.mkdir(parents=True, exist_ok=True) n_outcomes, n_negotiators = 5, 3 n_steps = 50 mechanism = SAOMechanism( outcomes=n_outcomes, n_steps=n_steps, offering_is_accepting=True, avoid_ultimatum=False, checkpoint_every=checkpoint_every, checkpoint_folder=new_folder, checkpoint_filename=filename, extra_checkpoint_info=None, exist_ok=exist_ok, single_checkpoint=single_checkpoint, ) ufuns = MappingUtilityFunction.generate_random(n_negotiators, outcomes=n_outcomes) for i in range(n_negotiators): mechanism.add(AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[i]) mechanism.run() files = list(new_folder.glob("*")) if 0 < checkpoint_every <= n_steps: if single_checkpoint: assert len(list(new_folder.glob("*"))) == 2 else: assert len(list(new_folder.glob("*"))) >= 2 * (max( 1, mechanism.state.step // checkpoint_every)) elif checkpoint_every > n_steps: assert len(list(new_folder.glob("*"))) == 2 else: assert len(list(new_folder.glob("*"))) == 0 runner = CheckpointRunner(folder=new_folder) assert len(runner.steps) * 2 == len(files) assert runner.current_step == -1 assert runner.loaded_object is None runner.step() assert runner.current_step == (0 if not single_checkpoint else runner.steps[-1]) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.reset() assert len(runner.steps) * 2 == len(files) assert runner.current_step == -1 assert runner.loaded_object is None runner.goto(runner.last_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.goto(runner.next_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.goto(runner.previous_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.goto(runner.first_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.reset() runner.run()
def test_can_run_from_checkpoint(tmp_path, checkpoint_every, exist_ok, copy, fork_after_reset): import shutil new_folder: Path = tmp_path / unique_name("empty", sep="") second_folder: Path = tmp_path / unique_name("second", sep="") new_folder.mkdir(parents=True, exist_ok=True) shutil.rmtree(new_folder) new_folder.mkdir(parents=True, exist_ok=True) second_folder.mkdir(parents=True, exist_ok=True) shutil.rmtree(second_folder) second_folder.mkdir(parents=True, exist_ok=True) filename = "mechanism" n_outcomes, n_negotiators = 5, 3 n_steps = 50 mechanism = SAOMechanism( outcomes=n_outcomes, n_steps=n_steps, offering_is_accepting=True, avoid_ultimatum=False, checkpoint_every=checkpoint_every, checkpoint_folder=new_folder, checkpoint_filename=filename, extra_checkpoint_info=None, exist_ok=exist_ok, single_checkpoint=False, ) ufuns = MappingUtilityFunction.generate_random(n_negotiators, outcomes=n_outcomes) for i in range(n_negotiators): mechanism.add( AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[i], aspiration_type="conceder", ) mechanism.run() files = list(new_folder.glob("*")) if 0 < checkpoint_every <= n_steps: assert len(list(new_folder.glob("*"))) >= 2 * (max( 1, mechanism.state.step // checkpoint_every)) elif checkpoint_every > n_steps: assert len(list(new_folder.glob("*"))) == 2 else: assert len(list(new_folder.glob("*"))) == 0 runner = CheckpointRunner(folder=new_folder) assert len(runner.steps) * 2 == len(files) assert runner.current_step == -1 assert runner.loaded_object is None runner.step() assert runner.current_step == 0 assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.reset() assert len(runner.steps) * 2 == len(files) assert runner.current_step == -1 assert runner.loaded_object is None runner.goto(runner.last_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.goto(runner.next_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.goto(runner.previous_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.goto(runner.first_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.reset() if fork_after_reset: m = runner.fork(copy_past_checkpoints=copy, folder=second_folder) assert m is None return runner.step() m = runner.fork(copy_past_checkpoints=copy, folder=second_folder) if copy: step = runner.current_step assert len(list(second_folder.glob("*"))) >= 2 assert len(list(second_folder.glob(f"*{step}.mechanism"))) > 0 else: assert len(list(second_folder.glob("*"))) == 0 assert isinstance(m, SAOMechanism) step = m.current_step m.step() assert m.current_step == step + 1 state = m.run() assert state.agreement is not None runner.reset() assert len(runner.steps) * 2 == len(files) assert runner.current_step == -1 assert runner.loaded_object is None runner.goto(runner.last_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.goto(runner.next_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.goto(runner.previous_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.goto(runner.first_step, exact=True) assert isinstance(runner.loaded_object, SAOMechanism) assert runner.loaded_object.state.step == runner.current_step runner.reset() runner.run()
def create( ctx, name, timeout, log, verbosity, reveal_names, runs, configs, max_runs, competitors, world_config, jcompetitors, non_competitors, compact, agents, log_ufuns, log_negs, raise_exceptions, steps_min, steps_max, path, cw, world_generator, config_generator, assigner, scorer, java_interop_class, ): if len(config_generator is None or config_generator.strip()) == 0: print( "ERROR: You did not specify a config generator. Use --config-generator to specify one and see the " "documentation of the create_tournament method in negmas.situated for details about it." "\nThe following must be explicitly specified to create a tournament: a world-generator, " "an assigner, a scorer, and a config-generator.") return -4 if len(world_generator is None or world_generator.strip()) == 0: print( "ERROR: You did not specify a world generator. Use --world-generator to specify one and see the " "documentation of the create_tournament method in negmas.situated for details about it." "\nThe following must be explicitly specified to create a tournament: a world-generator, " "an assigner, a scorer, and a config-generator.") return -3 if len(assigner is None or assigner.strip()) == 0: print( "ERROR: You did not specify an assigner. Use --assigner to specify one and see the documentation" " of the create_tournament method in negmas.situated for details about it." "\nThe following must be explicitly specified to create a tournament: a world-generator, " "an assigner, a scorer, and a config-generator.") return -2 if len(scorer is None or scorer.strip()) == 0: print( "ERROR: You did not specify a scorer. Use --scorer to specify one and see the documentation of the " "create_tournament method in negmas.situated for details about it." "\nThe following must be explicitly specified to create a tournament: a world-generator, " "an assigner, a scorer, and a config-generator.") return -1 if (jcompetitors is not None and len(jcompetitors) > 0 and len(java_interop_class.strip()) == 0): print( f"ERROR: You are passing java competitors but not java interop " f"class (use --java-interop-class " f" to pass the name of that class or do not pass java competitors" f" [--jcompetitors])") return -5 if len(path) > 0: sys.path.append(path) kwargs = {} if world_config is not None and len(world_config) > 0: for wc in world_config: kwargs.update(load(wc)) warning_n_runs = 2000 if timeout <= 0: timeout = None if name == "random": name = unique_name(base="", rand_digits=0) ctx.obj["tournament_name"] = name if max_runs <= 0: max_runs = None if compact: log_ufuns = False if not compact: if not reveal_names: print("You are running the tournament with --debug. Will reveal " "agent types in their names") reveal_names = True verbosity = max(1, verbosity) worlds_per_config = (None if max_runs is None else int( round(max_runs / (configs * runs)))) all_competitors = competitors.split(";") all_competitors_params = [dict() for _ in range(len(all_competitors))] if jcompetitors is not None and len(jcompetitors) > 0: jcompetitor_params = [{ "java_class_name": _ } for _ in jcompetitors.split(";")] jcompetitors = [java_interop_class] * len(jcompetitor_params) all_competitors += jcompetitors all_competitors_params += jcompetitor_params print( "You are using some Java agents. The tournament MUST run serially") if not jnegmas_bridge_is_running(): print( "Error: You are using java competitors but jnegmas bridge is not running\n\nTo correct this issue" " run the following command IN A DIFFERENT TERMINAL because it will block:\n\n" "$ negmas jnegmas") exit(1) permutation_size = 1 recommended = runs * configs * permutation_size if worlds_per_config is not None and worlds_per_config < 1: print( f"You need at least {(configs * runs)} runs even with a single permutation of managers." f".\n\nSet --max-runs to at least {(configs * runs)} (Recommended {recommended})" ) return if max_runs is not None and max_runs < recommended: print( f"You are running {max_runs} worlds only but it is recommended to set {max_runs} to at least " f"{recommended}. Will continue") steps = (steps_min, steps_max) if worlds_per_config is None: n_comp = len(all_competitors) n_worlds = permutation_size * runs * configs if n_worlds > warning_n_runs: print( f"You are running the maximum possible number of permutations for each configuration. This is roughly" f" {n_worlds} simulations (each for {steps} steps). That will take a VERY long time." f"\n\nYou can reduce the number of simulations by setting --configs>=1 (currently {configs}) or " f"--runs>= 1 (currently {runs}) to a lower value. " f"\nFinally, you can limit the maximum number of worlds to run by setting --max-runs=integer." ) # if ( # not input(f"Are you sure you want to run {n_worlds} simulations?") # .lower() # .startswith("y") # ): # exit(0) max_runs = int( input( f"Input the maximum number of simulations to run. Zero to run all of the {n_worlds} " f"simulations. ^C or a negative number to exit [0 : {n_worlds}]:" )) if max_runs == 0: max_runs = None if max_runs is not None and max_runs < 0: exit(0) worlds_per_config = (None if max_runs is None else int( round(max_runs / (configs * runs)))) if len(jcompetitors) > 0: print( "You are using java-competitors. The tournament will be run serially" ) parallelism = "serial" non_competitor_params = None if len(non_competitors) < 1: non_competitors = None else: non_competitors = non_competitors.split(";") print(f"Tournament will be run between {len(all_competitors)} agents: ") pprint(all_competitors) print("Non-competitors are: ") pprint(non_competitors) results = create_tournament( competitors=all_competitors, competitor_params=all_competitors_params, non_competitors=non_competitors, non_competitor_params=non_competitor_params, agent_names_reveal_type=reveal_names, n_competitors_per_world=cw, n_configs=configs, n_runs_per_world=runs, max_worlds_per_config=worlds_per_config, base_tournament_path=log, total_timeout=timeout, name=name, verbose=verbosity > 0, n_agents_per_competitor=agents, world_generator=world_generator, config_generator=config_generator, config_assigner=assigner, score_calculator=scorer, compact=compact, n_steps=steps, log_ufuns=log_ufuns, log_negotiations=log_negs, ignore_agent_exceptions=not raise_exceptions, ignore_contract_execution_exceptions=not raise_exceptions, parallelism=parallelism, **kwargs, ) ctx.obj["tournament_name"] = results.name ctx.obj["tournament_log_folder"] = log ctx.obj["compact"] = compact print( f"Saved all configs to {str(results)}\nTournament name is {results.name}" )
def main(worlds, factorial, variables, name, steps, compact, log, jobs): fixed_vars["n_steps"] = steps fixed_vars["compact"] = compact fixed_vars["no_logs"] = not log ind_vars = { "borrow_on_breach": [True, False], "buy_missing_products": [True, False], "production_buy_missing": [True, False], "exogenous_buy_missing": [True, False], "production_no_borrow": [True, False], "exogenous_no_borrow": [True, False], "exogenous_force_max": [True, False], "breach_penalty;production_penalty;exogenous_penalty": [ (0.15, 0.15, 0.15), (0.25, 0.25, 0.25), ], "interest_rate": [0.04, 0.08], "signing_delay": [0, 1], } if variables is not None and variables != "all": variables = ";".split(variables) ind_vars = {k: v for k, v in ind_vars.items() if k in variables} untested = list(set(ind_vars.keys()) - set(variables)) for v in untested: if ";" in v: vs = v.split(";") vals = random.sample(ind_vars[v], 1)[0] fixed_vars.update(dict(zip(vs, vals))) continue fixed_vars[v] = random.sample(ind_vars[v], 1)[0] constraints = ( Constraint( condition_vars=["borrow_on_breach"], condition_values=[[False]], conditioned_var="production_no_borrow", feasible_values=[True], ), Constraint( condition_vars=["borrow_on_breach"], condition_values=[[False]], conditioned_var="exogenous_no_borrow", feasible_values=[True], ), Constraint( condition_vars=["exogenous_force_max"], condition_values=[[False]], conditioned_var="production_no_borrow", feasible_values=[False], ), Constraint( condition_vars=["exogenous_force_max"], condition_values=[[True]], conditioned_var="exogenous_buy_missing", feasible_values=[True], ), ) print( f"Running experiment:\n" f"Independent Variables {list(ind_vars.keys())}\nDependent Variables: {list(dep_vars.keys())}\n" f"Untested Variables: {list(fixed_vars.keys())}\n" f"n. runs per world: {worlds} ({'factorial' if factorial else 'non-factorial'})" ) path = (Path.home() / "negmas" / "experiments" / unique_name("E" if name is None else name, add_time=True, sep="")) path.mkdir(parents=True, exist_ok=True) run(ind_vars, fixed_vars, worlds, factorial, constraints, n_jobs=jobs).to_csv(path / "results.csv")
def test_unique_name_with_path(tmpdir): a = unique_name(str(tmpdir)) assert a.startswith(str(tmpdir))
def test_unique_name_no_time(): assert len(unique_name("", add_time=False)) == 8
def create( ctx, name, steps, ttype, timeout, log, verbosity, reveal_names, runs, configs, max_runs, competitors, world_config, jcompetitors, non_competitors, compact, factories, agents, log_ufuns, log_negs, raise_exceptions, steps_min, steps_max, path, cw, ): if len(path) > 0: sys.path.append(path) kwargs = {} if world_config is not None and len(world_config) > 0: for wc in world_config: kwargs.update(load(wc)) warning_n_runs = 2000 if timeout <= 0: timeout = None if name == "random": name = unique_name(base="", rand_digits=0) ctx.obj["tournament_name"] = name if max_runs <= 0: max_runs = None if compact: log_ufuns = False if not compact: if not reveal_names: print( "You are running the tournament with --debug. Will reveal agent types in their names" ) reveal_names = True verbosity = max(1, verbosity) worlds_per_config = (None if max_runs is None else int( round(max_runs / (configs * runs)))) all_competitors = competitors.split(";") for i, cp in enumerate(all_competitors): if "." not in cp: all_competitors[i] = "negmas.apps.scml.factory_managers." + cp all_competitors_params = [dict() for _ in range(len(all_competitors))] if jcompetitors is not None and len(jcompetitors) > 0: jcompetitor_params = [{ "java_class_name": _ } for _ in jcompetitors.split(";")] for jp in jcompetitor_params: if "." not in jp["java_class_name"]: jp["java_class_name"] = ( "jnegmas.apps.scml.factory_managers." + jp["java_class_name"]) jcompetitors = ["negmas.apps.scml.JavaFactoryManager" ] * len(jcompetitor_params) all_competitors += jcompetitors all_competitors_params += jcompetitor_params print( "You are using some Java agents. The tournament MUST run serially") if not jnegmas_bridge_is_running(): print( "Error: You are using java competitors but jnegmas bridge is not running\n\nTo correct this issue" " run the following command IN A DIFFERENT TERMINAL because it will block:\n\n" "$ negmas jnegmas") exit(1) # if ttype.lower() == "anac2019std": # if ( # "negmas.apps.scml.factory_managers.GreedyFactoryManager" # not in all_competitors # ): # all_competitors.append( # "negmas.apps.scml.factory_managers.GreedyFactoryManager" # ) # all_competitors_params.append({}) permutation_size = len(all_competitors) if "sabotage" not in ttype else 1 recommended = runs * configs * permutation_size if worlds_per_config is not None and worlds_per_config < 1: print( f"You need at least {(configs * runs)} runs even with a single permutation of managers." f".\n\nSet --max-runs to at least {(configs * runs)} (Recommended {recommended})" ) return if max_runs is not None and max_runs < recommended: print( f"You are running {max_runs} worlds only but it is recommended to set {max_runs} to at least " f"{recommended}. Will continue") if ttype == "anac2019std": agents = 1 if steps is None: steps = (steps_min, steps_max) if worlds_per_config is None: n_comp = len(all_competitors) if ttype != "anac2019sabotage" else 2 n_worlds = permutation_size * runs * configs if n_worlds > warning_n_runs: print( f"You are running the maximum possible number of permutations for each configuration. This is roughly" f" {n_worlds} simulations (each for {steps} steps). That will take a VERY long time." f"\n\nYou can reduce the number of simulations by setting --configs>=1 (currently {configs}) or " f"--runs>= 1 (currently {runs}) to a lower value. " f"\nFinally, you can limit the maximum number of worlds to run by setting --max-runs=integer." ) # if ( # not input(f"Are you sure you want to run {n_worlds} simulations?") # .lower() # .startswith("y") # ): # exit(0) max_runs = int( input( f"Input the maximum number of simulations to run. Zero to run all of the {n_worlds} " f"simulations. ^C or a negative number to exit [0 : {n_worlds}]:" )) if max_runs == 0: max_runs = None if max_runs is not None and max_runs < 0: exit(0) worlds_per_config = (None if max_runs is None else int( round(max_runs / (configs * runs)))) if len(jcompetitors) > 0: print( "You are using java-competitors. The tournament will be run serially" ) parallelism = "serial" non_competitor_params = None if len(non_competitors) < 1: non_competitors = None else: non_competitors = non_competitors.split(";") for i, cp in enumerate(non_competitors): if "." not in cp: non_competitors[i] = "negmas.apps.scml.factory_managers." + cp if ttype.lower() == "anac2019std": if non_competitors is None: non_competitors = (DefaultGreedyManager, ) non_competitor_params = ({}, ) print( f"Tournament will be run between {len(all_competitors)} agents: ") pprint(all_competitors) print("Non-competitors are: ") pprint(non_competitors) results = create_tournament( competitors=all_competitors, competitor_params=all_competitors_params, non_competitors=non_competitors, non_competitor_params=non_competitor_params, agent_names_reveal_type=reveal_names, n_competitors_per_world=cw, n_configs=configs, n_runs_per_world=runs, max_worlds_per_config=worlds_per_config, base_tournament_path=log, total_timeout=timeout, name=name, verbose=verbosity > 0, n_agents_per_competitor=1, world_generator=anac2019_world_generator, config_generator=anac2019_config_generator, config_assigner=anac2019_assigner, score_calculator=balance_calculator, min_factories_per_level=factories, compact=compact, n_steps=steps, log_ufuns=log_ufuns, log_negotiations=log_negs, ignore_agent_exceptions=not raise_exceptions, ignore_contract_execution_exceptions=not raise_exceptions, **kwargs, ) elif ttype.lower() in ("anac2019collusion", "anac2019"): print( f"Tournament will be run between {len(all_competitors)} agents: ") pprint(all_competitors) print("Non-competitors are: ") pprint(non_competitors) results = create_tournament( competitors=all_competitors, competitor_params=all_competitors_params, non_competitors=non_competitors, non_competitor_params=non_competitor_params, agent_names_reveal_type=reveal_names, n_competitors_per_world=cw, n_configs=configs, n_runs_per_world=runs, max_worlds_per_config=worlds_per_config, base_tournament_path=log, total_timeout=timeout, name=name, verbose=verbosity > 0, n_agents_per_competitor=agents, world_generator=anac2019_world_generator, config_generator=anac2019_config_generator, config_assigner=anac2019_assigner, score_calculator=balance_calculator, min_factories_per_level=factories, compact=compact, n_steps=steps, log_ufuns=log_ufuns, log_negotiations=log_negs, ignore_agent_exceptions=not raise_exceptions, ignore_contract_execution_exceptions=not raise_exceptions, **kwargs, ) elif ttype.lower() == "anac2019sabotage": print( f"Tournament will be run between {len(all_competitors)} agents: ") pprint(all_competitors) print("Non-competitors are: ") pprint(non_competitors) results = create_tournament( competitors=all_competitors, competitor_params=all_competitors_params, agent_names_reveal_type=reveal_names, n_agents_per_competitor=agents, base_tournament_path=log, total_timeout=timeout, name=name, verbose=verbosity > 0, n_runs_per_world=runs, n_configs=configs, max_worlds_per_config=worlds_per_config, non_competitors=non_competitors, min_factories_per_level=factories, n_steps=steps, compact=compact, log_ufuns=log_ufuns, log_negotiations=log_negs, ignore_agent_exceptions=not raise_exceptions, ignore_contract_execution_exceptions=not raise_exceptions, non_competitor_params=non_competitor_params, world_generator=anac2019_world_generator, config_generator=anac2019_sabotage_config_generator, config_assigner=anac2019_sabotage_assigner, score_calculator=sabotage_effectiveness, **kwargs, ) else: raise ValueError(f"Unknown tournament type {ttype}") ctx.obj["tournament_name"] = results.name ctx.obj["tournament_log_folder"] = log ctx.obj["compact"] = compact print( f"Saved all configs to {str(results)}\nTournament name is {results.name}" )
def scml(steps, levels, neg_speedup, negotiator, agents, horizon, min_consumption, max_consumption, transport, time, neg_time, neg_steps, sign, guaranteed, lines, retrials, use_consumer, max_insurance, riskiness, log): params = { "steps": steps, "levels": levels, "neg_speedup": neg_speedup, "negotiator": negotiator, "agents": agents, "horizon": horizon, "min_consumption": min_consumption, "max_consumption": max_consumption, "transport": transport, "time": time, "neg_time": neg_time, "neg_steps": neg_steps, "sign": sign, "guaranteed": guaranteed, "lines": lines, "retrials": retrials, "use_consumer": use_consumer, "max_insurance": max_insurance, "riskiness": riskiness } neg_speedup = neg_speedup if neg_speedup is not None and neg_speedup > 0 else None if min_consumption == max_consumption: consumption = min_consumption else: consumption = (min_consumption, max_consumption) customer_kwargs = { 'negotiator_type': negotiator, 'consumption_horizon': horizon } miner_kwargs = {'negotiator_type': negotiator, 'n_retrials': retrials} factory_kwargs = { 'negotiator_type': negotiator, 'n_retrials': retrials, 'sign_only_guaranteed_contracts': guaranteed, 'use_consumer': use_consumer, 'riskiness': riskiness, 'max_insurance_premium': max_insurance } if log.startswith('~/'): log_dir = Path.home() / log[2:] else: log_dir = Path(log) log_dir = log_dir / unique_name(base='scml', add_time=True, rand_digits=0) log_dir = log_dir.absolute() os.makedirs(log_dir, exist_ok=True) log_file_name = str(log_dir / 'log.txt') stats_file_name = str(log_dir / 'stats.json') params_file_name = str(log_dir / 'params.json') world = SCMLWorld.single_path_world(log_file_name=log_file_name, n_steps=steps, negotiation_speed=neg_speedup, n_intermediate_levels=levels, n_miners=agents, n_consumers=agents, n_factories_per_level=agents, consumption=consumption, consumer_kwargs=customer_kwargs, miner_kwargs=miner_kwargs, manager_kwargs=factory_kwargs, transportation_delay=transport, time_limit=time, neg_time_limit=neg_time, neg_n_steps=neg_steps, default_signing_delay=sign, n_lines_per_factory=lines) failed = False strt = perf_counter() try: for i in progressbar.progressbar(range(world.n_steps), max_value=world.n_steps): elapsed = perf_counter() - strt if world.time_limit is not None and elapsed >= world.time_limit: break if not world.step(): break except Exception: exception = traceback.format_exc() failed = True elapsed = perf_counter() - strt def print_and_log(s): world.logdebug(s) print(s) world.logdebug(f'{pformat(world.stats, compact=True)}') world.logdebug( f'=================================================\n' f'steps: {steps}, horizon: {horizon}, time: {time}, levels: {levels}, agents_per_level: ' f'{agents}, lines: {lines}, guaranteed: {guaranteed}, negotiator: {negotiator}\n' f'consumption: {consumption}' f', transport_to: {transport}, sign: {sign}, speedup: {neg_speedup}, neg_steps: {neg_steps}' f', retrials: {retrials}' f', neg_time: {neg_time}\n' f'==================================================') save_stats(world=world, log_dir=log_dir, params=params) if len(world.saved_contracts) > 0: data = pd.DataFrame(world.saved_contracts) data = data.sort_values(['delivery_time']) data = data.loc[:, [ 'seller_type', 'buyer_type', 'seller_name', 'buyer_name', 'delivery_time', 'unit_price', 'quantity', 'product_name', 'n_neg_steps', 'signed_at', 'concluded_at', 'cfp' ]] print_and_log(tabulate(data, headers='keys', tablefmt='psql')) n_executed = sum(world.stats['n_contracts_executed']) n_negs = sum(world.stats["n_negotiations"]) n_contracts = len(world.saved_contracts) winners = [ f'{_.name} gaining {world.a2f[_.id].balance / world.a2f[_.id].initial_balance - 1.0:0.0%}' for _ in world.winners ] print_and_log(f'{n_contracts} contracts :-) [N. Negotiations: {n_negs}' f', Agreement Rate: {world.agreement_rate:0.0%}]') print_and_log(f'Executed: {world.contract_execution_fraction:0.0%}' f', Breached: {world.breach_rate:0.0%}' f', N. Executed: {n_executed}' f', Business size: {world.business_size}\n' f'Winners: {winners}\n' f'Running Time {humanize_time(elapsed)}') else: print_and_log('No contracts! :-(') print_and_log(f'Running Time {humanize_time(elapsed)}') if failed: print(exception) world.logdebug(exception) print(f'FAILED at step {world.current_step} of {world.n_steps}\n')
def test_unique_name_defaults(): a = unique_name("") assert len(a) == 8 + 1 + 6 + 8
def scml( steps, levels, neg_speedup, negotiator, agents, horizon, min_consumption, max_consumption, transport, time, neg_time, neg_steps, sign, guaranteed, lines, retrials, use_consumer, max_insurance, riskiness, competitors, jcompetitors, log, compact, log_ufuns, log_negs, reserved_value, balance, shared_profile, raise_exceptions, path, world_config, ): kwargs = dict( no_bank=True, no_insurance=False, prevent_cfp_tampering=True, ignore_negotiated_penalties=False, neg_step_time_limit=10, breach_penalty_society=0.02, premium=0.03, premium_time_increment=0.1, premium_breach_increment=0.001, max_allowed_breach_level=None, breach_penalty_society_min=0.0, breach_penalty_victim=0.0, breach_move_max_product=True, transfer_delay=0, start_negotiations_immediately=False, catalog_profit=0.15, financial_reports_period=10, default_price_for_products_without_one=1, compensation_fraction=0.5, ) if world_config is not None and len(world_config) > 0: for wc in world_config: kwargs.update(load(wc)) if len(path) > 0: sys.path.append(path) if max_insurance < 0: warnings.warn( f"Negative max insurance ({max_insurance}) is deprecated. Set --max-insurance=inf for always " f"buying and --max-insurance=0.0 for never buying. Will continue assuming --max-insurance=inf" ) max_insurance = float("inf") if "." not in negotiator: negotiator = "negmas.sao." + negotiator params = { "steps": steps, "levels": levels, "neg_speedup": neg_speedup, "negotiator": negotiator, "agents": agents, "horizon": horizon, "min_consumption": min_consumption, "max_consumption": max_consumption, "transport": transport, "time": time, "neg_time": neg_time, "neg_steps": neg_steps, "sign": sign, "guaranteed": guaranteed, "lines": lines, "retrials": retrials, "use_consumer": use_consumer, "max_insurance": max_insurance, "riskiness": riskiness, } if compact: log_ufuns = False log_negs = False neg_speedup = neg_speedup if neg_speedup is not None and neg_speedup > 0 else None if min_consumption == max_consumption: consumption = min_consumption else: consumption = (min_consumption, max_consumption) customer_kwargs = { "negotiator_type": negotiator, "consumption_horizon": horizon } miner_kwargs = {"negotiator_type": negotiator, "n_retrials": retrials} factory_kwargs = { "negotiator_type": negotiator, "n_retrials": retrials, "sign_only_guaranteed_contracts": guaranteed, "use_consumer": use_consumer, "riskiness": riskiness, "max_insurance_premium": max_insurance, "reserved_value": reserved_value, } if log.startswith("~/"): log_dir = Path.home() / log[2:] else: log_dir = Path(log) world_name = unique_name(base="scml", add_time=True, rand_digits=0) log_dir = log_dir / world_name log_dir = log_dir.absolute() os.makedirs(log_dir, exist_ok=True) exception = None def _no_default(s): return not (s.startswith("negmas.apps.scml") and s.endswith("GreedyFactoryManager")) all_competitors = competitors.split(";") for i, cp in enumerate(all_competitors): if "." not in cp: all_competitors[i] = "negmas.apps.scml.factory_managers." + cp all_competitors_params = [ dict() if _no_default(_) else factory_kwargs for _ in all_competitors ] if jcompetitors is not None and len(jcompetitors) > 0: jcompetitor_params = [{ "java_class_name": _ } for _ in jcompetitors.split(";")] for jp in jcompetitor_params: if "." not in jp["java_class_name"]: jp["java_class_name"] = ( "jnegmas.apps.scml.factory_managers." + jp["java_class_name"]) jcompetitors = ["negmas.apps.scml.JavaFactoryManager" ] * len(jcompetitor_params) all_competitors += jcompetitors all_competitors_params += jcompetitor_params print( "You are using some Java agents. The tournament MUST run serially") parallelism = "serial" if not jnegmas_bridge_is_running(): print( "Error: You are using java competitors but jnegmas bridge is not running\n\nTo correct this issue" " run the following command IN A DIFFERENT TERMINAL because it will block:\n\n" "$ negmas jnegmas") exit(1) world = SCMLWorld.chain_world( n_steps=steps, negotiation_speed=neg_speedup, n_intermediate_levels=levels, n_miners=agents, n_consumers=agents, n_factories_per_level=agents, consumption=consumption, consumer_kwargs=customer_kwargs, miner_kwargs=miner_kwargs, default_manager_params=factory_kwargs, transportation_delay=transport, time_limit=time, neg_time_limit=neg_time, neg_n_steps=neg_steps, default_signing_delay=sign, n_lines_per_factory=lines, compact=compact, agent_names_reveal_type=True, log_ufuns=log_ufuns, manager_types=all_competitors, manager_params=all_competitors_params, log_negotiations=log_negs, log_folder=log_dir, name=world_name, shared_profile_per_factory=shared_profile, initial_wallet_balances=balance, ignore_agent_exceptions=not raise_exceptions, ignore_contract_execution_exceptions=not raise_exceptions, **kwargs, ) failed = False strt = perf_counter() try: for i in progressbar.progressbar(range(world.n_steps), max_value=world.n_steps): elapsed = perf_counter() - strt if world.time_limit is not None and elapsed >= world.time_limit: break if not world.step(): break except Exception: exception = traceback.format_exc() failed = True elapsed = perf_counter() - strt def print_and_log(s): world.logdebug(s) print(s) world.logdebug(f"{pformat(world.stats, compact=True)}") world.logdebug( f"=================================================\n" f"steps: {steps}, horizon: {horizon}, time: {time}, levels: {levels}, agents_per_level: " f"{agents}, lines: {lines}, guaranteed: {guaranteed}, negotiator: {negotiator}\n" f"consumption: {consumption}" f", transport_to: {transport}, sign: {sign}, speedup: {neg_speedup}, neg_steps: {neg_steps}" f", retrials: {retrials}" f", neg_time: {neg_time}\n" f"==================================================") save_stats(world=world, log_dir=log_dir, params=params) if len(world.saved_contracts) > 0: data = pd.DataFrame(world.saved_contracts) data = data.sort_values(["delivery_time"]) data = data.loc[data.signed_at >= 0, [ "seller_type", "buyer_type", "seller_name", "buyer_name", "delivery_time", "unit_price", "quantity", "product_name", "n_neg_steps", "signed_at", ], ] data.columns = [ "seller_type", "buyer_type", "seller", "buyer", "t", "price", "q", "product", "steps", "signed", ] print_and_log(tabulate(data, headers="keys", tablefmt="psql")) data["product_id"] = np.array([_.id for _ in data["product"].values]) d2 = (data.loc[(~(data["signed"].isnull())) & (data["signed"] > -1), :].groupby( ["product_id"]).apply(lambda x: pd.DataFrame([{ "uprice": np.sum(x["price"] * x["q"]) / np.sum(x["q"]), "quantity": np.sum(x["q"]), }]))) d2 = d2.reset_index().sort_values(["product_id"]) products = dict(zip([_.id for _ in world.products], world.products)) d2["Product"] = np.array( [products[_] for _ in d2["product_id"].values]) d2 = d2.loc[:, ["Product", "uprice", "quantity"]] d2.columns = ["Product", "Avg. Unit Price", "Total Quantity"] print_and_log(tabulate(d2, headers="keys", tablefmt="psql")) n_executed = sum(world.stats["n_contracts_executed"]) n_negs = sum(world.stats["n_negotiations"]) n_contracts = len(world.saved_contracts) try: agent_scores = sorted( [[_.name, world.a2f[_.id].total_balance] for _ in world.agents.values() if isinstance(_, FactoryManager)], key=lambda x: x[1], reverse=True, ) agent_scores = pd.DataFrame(data=np.array(agent_scores), columns=["Agent", "Final Balance"]) print_and_log( tabulate(agent_scores, headers="keys", tablefmt="psql")) except: pass winners = [ f"{_.name} gaining {world.a2f[_.id].total_balance / world.a2f[_.id].initial_balance - 1.0:0.0%}" for _ in world.winners ] print_and_log( f"{n_contracts} contracts :-) [N. Negotiations: {n_negs}, Agreement Rate: " f"{world.agreement_rate:0.0%}]" f" (rounds/successful negotiation: {world.n_negotiation_rounds_successful:5.2f}, " f"rounds/broken negotiation: {world.n_negotiation_rounds_failed:5.2f})" ) print_and_log( f"Cancelled: {world.cancellation_rate:0.0%}, Executed: {world.contract_execution_fraction:0.0%}" f", Breached: {world.breach_rate:0.0%}, N. Executed: {n_executed}, Business size: " f"{world.business_size}\n" f"Winners: {winners}\n" f"Running Time {humanize_time(elapsed)}") else: print_and_log("No contracts! :-(") print_and_log(f"Running Time {humanize_time(elapsed)}") if failed: print(exception) world.logdebug(exception) print(f"FAILED at step {world.current_step} of {world.n_steps}\n")