示例#1
0
def create_display_boundaries(pg_cur, settings):
    # Step 3 of 3 : create web optimised versions of the census boundaries
    start_time = datetime.now()

    # create schema
    if settings['web_schema'] != "public":
        pg_cur.execute(
            "CREATE SCHEMA IF NOT EXISTS {0} AUTHORIZATION {1}".format(
                settings['web_schema'], settings['pg_user']))

    # prepare boundaries for all tiled map zoom levels
    create_sql_list = list()
    insert_sql_list = list()
    vacuum_sql_list = list()

    for boundary_dict in settings['bdy_table_dicts']:
        boundary_name = boundary_dict["boundary"]

        if boundary_name != "mb":
            id_field = boundary_dict["id_field"]
            name_field = boundary_dict["name_field"]
            area_field = boundary_dict["area_field"]

            input_pg_table = "{0}_{1}_aust".format(boundary_name,
                                                   settings["census_year"])
            pg_table = "{0}".format(boundary_name)

            # build create table statement
            create_table_list = list()
            create_table_list.append("DROP TABLE IF EXISTS {0}.{1} CASCADE;")
            create_table_list.append("CREATE TABLE {0}.{1} (")

            # build column list
            column_list = list()
            column_list.append("id text NOT NULL PRIMARY KEY")
            column_list.append("name text NOT NULL")
            column_list.append("area double precision NOT NULL")
            column_list.append("population double precision NOT NULL")
            column_list.append("geom geometry(MultiPolygon, 4283) NULL")

            for zoom_level in range(4, 18):
                display_zoom = str(zoom_level).zfill(2)
                column_list.append(
                    "geojson_{0} jsonb NOT NULL".format(display_zoom))

            # add columns to create table statement and finish it
            create_table_list.append(",".join(column_list))
            create_table_list.append(") WITH (OIDS=FALSE);")
            create_table_list.append("ALTER TABLE {0}.{1} OWNER TO {2};")
            create_table_list.append(
                "CREATE INDEX {1}_geom_idx ON {0}.{1} USING gist (geom);")
            create_table_list.append(
                "ALTER TABLE {0}.{1} CLUSTER ON {1}_geom_idx")

            sql = "".join(create_table_list).format(settings['web_schema'],
                                                    pg_table,
                                                    settings['pg_user'])
            create_sql_list.append(sql)

            # get population field and table
            if boundary_name[:1] == "i":
                pop_stat = settings['indigenous_population_stat']
                pop_table = settings['indigenous_population_table']
            else:
                pop_stat = settings['population_stat']
                pop_table = settings['population_table']

            # print(boundary_name)
            # print(pop_stat + " - " + pop_table)

            # build insert statement
            insert_into_list = list()
            insert_into_list.append("INSERT INTO {0}.{1}".format(
                settings['web_schema'], pg_table))
            insert_into_list.append(
                "SELECT bdy.{0} AS id, {1} AS name, SUM(bdy.{2}) AS area, tab.{3} AS population,"
                .format(id_field, name_field, area_field, pop_stat))

            # thin geometry to make querying faster
            tolerance = utils.get_tolerance(10)
            insert_into_list.append(
                "ST_Transform(ST_Multi(ST_Union(ST_SimplifyVW("
                "ST_Transform(geom, 3577), {0}))), 4283),".format(tolerance, ))

            # create statements for geojson optimised for each zoom level
            geojson_list = list()

            for zoom_level in range(4, 18):
                # thin geometries to a default tolerance per zoom level
                tolerance = utils.get_tolerance(zoom_level)
                # trim coords to only the significant ones
                decimal_places = utils.get_decimal_places(zoom_level)

                geojson_list.append(
                    "ST_AsGeoJSON(ST_Transform(ST_Multi(ST_Union(ST_SimplifyVW(ST_Transform("
                    "bdy.geom, 3577), {0}))), 4283), {1})::jsonb".format(
                        tolerance, decimal_places))

            insert_into_list.append(",".join(geojson_list))
            insert_into_list.append("FROM {0}.{1} AS bdy".format(
                settings['boundary_schema'], input_pg_table))
            insert_into_list.append("INNER JOIN {0}.{1}_{2} AS tab".format(
                settings['data_schema'], boundary_name, pop_table))
            insert_into_list.append("ON bdy.{0} = tab.{1}".format(
                id_field, settings["region_id_field"]))
            insert_into_list.append("WHERE bdy.geom IS NOT NULL")
            insert_into_list.append("GROUP BY {0}, {1}, {2}".format(
                id_field, name_field, pop_stat))

            sql = " ".join(insert_into_list)
            insert_sql_list.append(sql)

            vacuum_sql_list.append("VACUUM ANALYZE {0}.{1}".format(
                settings['web_schema'], pg_table))

    # print("\n".join(insert_sql_list))

    utils.multiprocess_list("sql", create_sql_list, settings, logger)
    utils.multiprocess_list("sql", insert_sql_list, settings, logger)
    utils.multiprocess_list("sql", vacuum_sql_list, settings, logger)

    logger.info(
        "\t- Step 3 of 3 : web optimised boundaries created : {0}".format(
            datetime.now() - start_time))
示例#2
0
def denominations_combinations(
        currency: Currency,
        amount: float,
        max_solutions=1_000) -> Tuple[int, List[Dict[float, int]]]:
    """
    This function returns the number of different ways that value given as parameter can be achieved
    by using all the possible combinations of the denominations of the given currency.
    :param currency: currency to use
    :param amount: the total amount to be achieved
    :param max_solutions: the maximum number of solutions that must be returned. After 1_000, memory usage increases
    :return: the number of all the possible combinations of denominations that match the amount
    """
    amount = round(amount, 2)
    amount_decimal_places = get_decimal_places(amount)

    den_decimal_places = 0
    denominations = []
    unused_denominations = []
    for den in currency.iter_denominations():
        if den <= amount:
            den_decimal_places = max(den_decimal_places,
                                     get_decimal_places(round(
                                         den, 2)))  # max is needed
            denominations.append(round(den, 2))
        else:
            unused_denominations.append(den)

    if amount_decimal_places > den_decimal_places:
        # if the smallest denomination has less decimal places than the amount, then a solution does not exist
        return 0, []

    # the amount and the denominations are multiplied by the minimum possible value
    # e.g. if amount = 2.20 and den = [0.10, 0.20, 0.50] then everything is multiplied by 10^1
    amount = int(round(amount, 2) * (10**den_decimal_places))
    int_denominations = [
        int(denomination * (10**den_decimal_places))
        for denomination in denominations
    ]
    int2real = {k: v for k, v in zip(int_denominations, denominations)}

    # dynamic programming solution
    base_sol = {denomination: 0 for denomination in denominations}
    sol = [[(0, [])] * (amount + 1) for _ in range(len(int_denominations))]
    for i in range(len(int_denominations)):
        for j in range(amount + 1):
            if j == 0:
                sol[i][j] = (1, [base_sol]
                             )  # base solution, take zero denominations
                continue
            if i == 0:
                if j % int_denominations[i] == 0:
                    d_sol = dict(base_sol)
                    d_sol[int2real[
                        int_denominations[i]]] = j // int_denominations[i]
                    sol[i][j] = (1, [d_sol])
                else:
                    sol[i][j] = (0, [])
                continue
            if j >= int_denominations[i]:
                n_sol = sol[i - 1][j][0] + sol[i][j - int_denominations[i]][0]
                d_sol = []
                d_sol += sol[i - 1][j][1][:]
                d_sol += add_den_usage(int2real[int_denominations[i]],
                                       sol[i][j - int_denominations[i]][1],
                                       max_solutions=max_solutions)
                sol[i][j] = (n_sol, d_sol[-max_solutions:])
            else:
                sol[i][j] = (sol[i - 1][j][0], sol[i - 1][j][1][:])
            sol[i - 1][j] = (sol[i - 1][j][0], [])  # Memory usage optimization

    unused_sol = {denomination: 0 for denomination in unused_denominations}
    for s in sol[-1][-1][1]:
        s.update(unused_sol)
    return sol[-1][-1]