Browse Source

Add in-memory only databases

master
Jirka Sejkora 3 years ago
parent
commit
083d6a97b9
  1. 4
      src/combine-layouts.rs
  2. 4
      src/combine.rs
  3. 95
      src/db.rs
  4. 4
      src/import-logs.rs
  5. 4
      src/main.rs
  6. 8
      src/population.rs

4
src/combine-layouts.rs

@ -1,4 +1,4 @@
use db::{LayoutDB, SavedLayout}; use db::{SqliteLayoutDB, SavedLayout};
use city::{City, House}; use city::{City, House};
use itertools::Itertools; use itertools::Itertools;
use crate::combine::transpose_layout; use crate::combine::transpose_layout;
@ -13,7 +13,7 @@ enum LastStep {
} }
fn main() { fn main() {
let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB"); let mut db = SqliteLayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB");
eprintln!("Loaded the DB, {} stored layouts", db.layouts().len()); eprintln!("Loaded the DB, {} stored layouts", db.layouts().len());
let city = City::read_from_file("01.in", city::INPUT_CITY_WIDTH, city::INPUT_CITY_HEIGHT); let city = City::read_from_file("01.in", city::INPUT_CITY_WIDTH, city::INPUT_CITY_HEIGHT);

4
src/combine.rs

@ -1,5 +1,5 @@
use crate::city; use crate::city;
use crate::db::{LayoutDB, SavedLayout, MergeLowerBound}; use crate::db::{SqliteLayoutDB, SavedLayout, MergeLowerBound, LayoutDB};
use crate::city::{City, House}; use crate::city::{City, House};
use itertools::Itertools; use itertools::Itertools;
use itertools::iproduct; use itertools::iproduct;
@ -37,7 +37,7 @@ impl CompatibilityCache {
} }
} }
pub fn create_new_best_combination(city: &City, left_layouts: &Vec<SavedLayout>, right_layouts: &Vec<SavedLayout>, db: &mut LayoutDB, cache: &mut CompatibilityCache, transposed: bool) -> bool { pub fn create_new_best_combination<TDB: LayoutDB>(city: &City, left_layouts: &Vec<SavedLayout>, right_layouts: &Vec<SavedLayout>, db: &mut TDB, cache: &mut CompatibilityCache, transposed: bool) -> bool {
let mut best_price = left_layouts.iter().chain(right_layouts.iter()) let mut best_price = left_layouts.iter().chain(right_layouts.iter())
.map(|layout| city::get_price(&city, layout.houses())) .map(|layout| city::get_price(&city, layout.houses()))
.min(); .min();

95
src/db.rs

@ -2,8 +2,12 @@ use crate::city::House;
use rusqlite::{Connection, NO_PARAMS, params, Result}; use rusqlite::{Connection, NO_PARAMS, params, Result};
use std::collections::HashMap; use std::collections::HashMap;
pub struct LayoutDB { pub struct SqliteLayoutDB {
connection: Connection, connection: Connection,
memory_db: MemoryLayoutDB,
}
pub struct MemoryLayoutDB {
layouts: Vec<SavedLayout>, layouts: Vec<SavedLayout>,
merge_lower_bounds: HashMap<(usize, usize, bool), MergeLowerBound>, merge_lower_bounds: HashMap<(usize, usize, bool), MergeLowerBound>,
} }
@ -57,7 +61,76 @@ impl SavedLayout {
} }
} }
impl LayoutDB { impl MemoryLayoutDB {
pub fn new(layouts: Vec<SavedLayout>, merge_lower_bounds: HashMap<(usize, usize, bool), MergeLowerBound>) -> Self {
MemoryLayoutDB { layouts, merge_lower_bounds }
}
// This exists for use by the SqliteLayoutDB
fn add_layout_with_id(&mut self, houses: &Vec<House>, layout_id: usize, fully_optimized: bool) {
self.layouts.push(SavedLayout { id: layout_id, houses: houses.clone() });
}
}
pub trait LayoutDB {
fn layouts(&self) -> &Vec<SavedLayout>;
fn add_layout(&mut self, houses: &Vec<House>, fully_optimized: bool);
fn get_merge_lower_bound(&self, left_layout: &SavedLayout, right_layout: &SavedLayout, y_axis: bool) -> Option<u32>;
fn add_merge_lower_bound(&mut self, lower_bound: MergeLowerBound);
fn add_merge_lower_bounds(&mut self, lower_bounds: Vec<MergeLowerBound>);
}
impl LayoutDB for MemoryLayoutDB {
fn layouts(&self) -> &Vec<SavedLayout> {
&self.layouts
}
fn add_layout(&mut self, houses: &Vec<House>, fully_optimized: bool) {
let layout_id = self.layouts.iter().map(|x| x.id).max().unwrap_or_default() + 1;
self.layouts.push(SavedLayout { id: layout_id, houses: houses.clone() });
}
fn get_merge_lower_bound(&self, left_layout: &SavedLayout, right_layout: &SavedLayout, y_axis: bool) -> Option<u32> {
if let Some(bound) = self.merge_lower_bounds.get(&(left_layout.id, right_layout.id, y_axis)) {
return Some(bound.price);
}
None
}
fn add_merge_lower_bound(&mut self, lower_bound: MergeLowerBound) {
self.merge_lower_bounds.insert((lower_bound.left_layout_id, lower_bound.right_layout_id, lower_bound.y_axis), lower_bound);
}
fn add_merge_lower_bounds(&mut self, lower_bounds: Vec<MergeLowerBound>) {
for lower_bound in lower_bounds {
self.merge_lower_bounds.insert((lower_bound.left_layout_id, lower_bound.right_layout_id, lower_bound.y_axis), lower_bound);
}
}
}
impl LayoutDB for SqliteLayoutDB {
fn layouts(&self) -> &Vec<SavedLayout> {
self.layouts()
}
fn add_layout(&mut self, houses: &Vec<House>, fully_optimized: bool) {
self.add_layout(houses, fully_optimized).unwrap();
}
fn get_merge_lower_bound(&self, left_layout: &SavedLayout, right_layout: &SavedLayout, y_axis: bool) -> Option<u32> {
self.get_merge_lower_bound(left_layout, right_layout, y_axis)
}
fn add_merge_lower_bound(&mut self, lower_bound: MergeLowerBound) {
self.add_merge_lower_bound(lower_bound).unwrap()
}
fn add_merge_lower_bounds(&mut self, lower_bounds: Vec<MergeLowerBound>) {
self.add_merge_lower_bounds(lower_bounds).unwrap()
}
}
impl SqliteLayoutDB {
pub fn from_file(filename: &str) -> Result<Self> { pub fn from_file(filename: &str) -> Result<Self> {
let connection = Connection::open(filename)?; let connection = Connection::open(filename)?;
let mut layouts: HashMap<u32, Vec<(u32, u32)>> = HashMap::new(); let mut layouts: HashMap<u32, Vec<(u32, u32)>> = HashMap::new();
@ -102,11 +175,12 @@ impl LayoutDB {
} }
).collect(); ).collect();
Ok(LayoutDB { connection, layouts, merge_lower_bounds: merges }) let memory_db = MemoryLayoutDB::new(layouts, merges);
Ok(SqliteLayoutDB { connection, memory_db})
} }
pub fn layouts(&self) -> &Vec<SavedLayout> { pub fn layouts(&self) -> &Vec<SavedLayout> {
&self.layouts self.memory_db.layouts()
} }
pub fn add_layout(&mut self, houses: &Vec<House>, fully_optimized: bool) -> Result<()> { pub fn add_layout(&mut self, houses: &Vec<House>, fully_optimized: bool) -> Result<()> {
@ -119,15 +193,12 @@ impl LayoutDB {
params![layout_id, house.x as u32, house.y as u32])?; params![layout_id, house.x as u32, house.y as u32])?;
} }
transaction.commit()?; transaction.commit()?;
self.layouts.push(SavedLayout { id: layout_id as usize, houses: houses.clone() }); self.memory_db.add_layout_with_id(houses, layout_id as usize, fully_optimized);
Ok(()) Ok(())
} }
pub fn get_merge_lower_bound(&self, left_layout: &SavedLayout, right_layout: &SavedLayout, y_axis: bool) -> Option<u32> { pub fn get_merge_lower_bound(&self, left_layout: &SavedLayout, right_layout: &SavedLayout, y_axis: bool) -> Option<u32> {
if let Some(bound) = self.merge_lower_bounds.get(&(left_layout.id, right_layout.id, y_axis)) { self.memory_db.get_merge_lower_bound(left_layout, right_layout, y_axis)
return Some(bound.price);
}
None
} }
pub fn add_merge_lower_bound(&mut self, lower_bound: MergeLowerBound) -> Result<()> { pub fn add_merge_lower_bound(&mut self, lower_bound: MergeLowerBound) -> Result<()> {
@ -140,13 +211,13 @@ impl LayoutDB {
], ],
)?; )?;
transaction.commit()?; transaction.commit()?;
self.merge_lower_bounds.insert((lower_bound.left_layout_id, lower_bound.right_layout_id, lower_bound.y_axis), lower_bound); self.memory_db.add_merge_lower_bound(lower_bound);
Ok(()) Ok(())
} }
pub fn add_merge_lower_bounds(&mut self, lower_bounds: Vec<MergeLowerBound>) -> Result<()> { pub fn add_merge_lower_bounds(&mut self, lower_bounds: Vec<MergeLowerBound>) -> Result<()> {
let transaction = self.connection.transaction()?; let transaction = self.connection.transaction()?;
for lower_bound in lower_bounds { for lower_bound in &lower_bounds {
transaction.execute("INSERT INTO merge_lower_bounds (left_layout_id, right_layout_id, axis, price) VALUES (?1, ?2, ?3, ?4) ON CONFLICT(left_layout_id, right_layout_id) DO UPDATE SET price = ?4", transaction.execute("INSERT INTO merge_lower_bounds (left_layout_id, right_layout_id, axis, price) VALUES (?1, ?2, ?3, ?4) ON CONFLICT(left_layout_id, right_layout_id) DO UPDATE SET price = ?4",
params![lower_bound.left_layout_id as u32, params![lower_bound.left_layout_id as u32,
lower_bound.right_layout_id as u32, lower_bound.right_layout_id as u32,
@ -154,9 +225,9 @@ impl LayoutDB {
lower_bound.price lower_bound.price
], ],
)?; )?;
self.merge_lower_bounds.insert((lower_bound.left_layout_id, lower_bound.right_layout_id, lower_bound.y_axis), lower_bound);
} }
transaction.commit()?; transaction.commit()?;
self.memory_db.add_merge_lower_bounds(lower_bounds);
Ok(()) Ok(())
} }
} }

4
src/import-logs.rs

@ -2,7 +2,7 @@ use std::io;
use std::io::BufRead; use std::io::BufRead;
use regex::Regex; use regex::Regex;
use crate::city::House; use crate::city::House;
use crate::db::LayoutDB; use crate::db::SqliteLayoutDB;
mod city; mod city;
mod db; mod db;
@ -14,7 +14,7 @@ enum State {
} }
fn main() { fn main() {
let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB"); let mut db = SqliteLayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB");
let stdin = io::stdin(); let stdin = io::stdin();
let price_regex = Regex::new("^Price ([0-9]*), seed ([0-9]*)$").unwrap(); let price_regex = Regex::new("^Price ([0-9]*), seed ([0-9]*)$").unwrap();

4
src/main.rs

@ -4,7 +4,7 @@ use std::fmt;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use city::{HouseLayout, City, House}; use city::{HouseLayout, City, House};
use crate::db::LayoutDB; use crate::db::SqliteLayoutDB;
use crate::population::{build_house_probabilities, populate_from_saved_layout}; use crate::population::{build_house_probabilities, populate_from_saved_layout};
use itertools::Itertools; use itertools::Itertools;
@ -23,7 +23,7 @@ enum RunType {
} }
fn main() { fn main() {
let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB"); let mut db = SqliteLayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB");
eprintln!("Loaded the DB, {} stored layouts", db.layouts().len()); eprintln!("Loaded the DB, {} stored layouts", db.layouts().len());
let city = City::read_from_file("01.in", city::INPUT_CITY_WIDTH, city::INPUT_CITY_HEIGHT); let city = City::read_from_file("01.in", city::INPUT_CITY_WIDTH, city::INPUT_CITY_HEIGHT);

8
src/population.rs

@ -1,7 +1,7 @@
use rand::Rng; use rand::Rng;
use crate::city::{House, HouseLayout, City}; use crate::city::{House, HouseLayout, City};
use rand::prelude::*; use rand::prelude::*;
use crate::db::{LayoutDB, SavedLayout}; use crate::db::{SqliteLayoutDB, SavedLayout, LayoutDB};
use crate::city; use crate::city;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Add; use std::ops::Add;
@ -26,7 +26,7 @@ pub fn populate_random(layout: &mut HouseLayout, rng: &mut StdRng) {
} }
} }
pub fn build_house_probabilities(city: &City, db: &LayoutDB, min_score: f64, max_score: f64) -> (WeightedIndex<f64>, Vec<House>){ pub fn build_house_probabilities<TDB : LayoutDB>(city: &City, db: &TDB, min_score: f64, max_score: f64) -> (WeightedIndex<f64>, Vec<House>){
let mut counts: HashMap<House, f64> = HashMap::new(); let mut counts: HashMap<House, f64> = HashMap::new();
for layout in db.layouts() { for layout in db.layouts() {
let price = city::get_price(&city, layout.houses()) as f64; let price = city::get_price(&city, layout.houses()) as f64;
@ -44,8 +44,8 @@ pub fn build_house_probabilities(city: &City, db: &LayoutDB, min_score: f64, max
(index, houses.iter().map(|(house, _)| *house).collect()) (index, houses.iter().map(|(house, _)| *house).collect())
} }
pub fn populate_using_db(layout: &mut HouseLayout, mut rng: &mut StdRng, db: &LayoutDB, min_score: f64, max_score: f64, db_probability: f64) { pub fn populate_using_db<TDB: LayoutDB>(layout: &mut HouseLayout, mut rng: &mut StdRng, db: &TDB, min_score: f64, max_score: f64, db_probability: f64) {
let (mut index, houses) = build_house_probabilities(&layout.city, &db, min_score, max_score); let (mut index, houses) = build_house_probabilities(&layout.city, db, min_score, max_score);
loop { loop {
if rng.gen::<f64>() < db_probability { if rng.gen::<f64>() < db_probability {

Loading…
Cancel
Save