Source code for dnaweaver.DnaSupplier.DnaSupplier

# -*- coding: utf-8 -*-

from collections import defaultdict

import numpy as np
from ..DnaQuote import DnaQuote
from ..biotools import SequenceString

from . import mixins


[docs]class DnaSupplier( mixins.JsonImportMixin, mixins.ConstraintsMixin, mixins.SupplyNetworkMixin ): """Base class for all DnaSuppliers, which are the elements of the supply networks used to define assembly problems in DnaWeaver.""" min_basepair_price = 0
[docs] def get_quote( self, sequence, max_lead_time=None, max_price=None, with_assembly_plan=False, time_resolution=1.0, ): """Return a DnaQuote with price, lead time, etc. for a given sequence. Parameters ---------- sequence (str) The sequence submitted to the Dna Source for a quote. max_lead_time (float) If provided, the quote returned is the best quote (price-wise) whose lead time is less or equal to max_lead_time. max_price (float) If provided, the quote returned is the least-lead-time quote whose price is below or equal to `max_price`. This is done using bisection and can be slow as it requires to re-compute the problem many times. Note that either this parameter or `max_lead_time` must be None. with_assembly_plan If True, the assembly plan is added to the quote. time_resolution Time resolution for the bisecting search if `max_price` is not None. Returns ------- A DnaQuote object. """ if hasattr(sequence, "seq"): # Use a simpler format which still remembers the topology sequence = SequenceString.from_record(sequence) if max_lead_time is None: max_lead_time = np.inf if self.memoize: args = ( hash(sequence), max_lead_time, max_price, with_assembly_plan, ) quote = self.memoize_dict.get(args, None) if quote is not None: return quote if not self.verify_constraints(sequence): quote = DnaQuote( self, sequence, accepted=False, message="Sequence does not pass constraints.", ) elif max_price is not None: quote = self.get_best_lead_time_under_price_limit( sequence, max_price=max_price, time_resolution=time_resolution, with_assembly_plan=with_assembly_plan, ) else: quote = self.get_best_price( sequence, max_lead_time=max_lead_time, with_assembly_plan=with_assembly_plan, ) if self.memoize: self.memoize_dict[args] = quote return quote
def __repr__(self): return self.name
[docs] def get_best_lead_time_under_price_limit( self, sequence, max_price, time_resolution, with_assembly_plan=False, ): """Return the quote with fastest lead time under the budget constraint/ Parameters ---------- sequence (str) The sequence submitted to the Dna Source for a quote. max_price (float) If provided, the quote returned is the least-lead-time quote whose price is below or equal to `max_price`. This is done using bisection and can be slow as it requires to re-compute the problem many times. Note that either this parameter or `max_lead_time` must be None. with_assembly_plan If True, the assembly plan is added to the quote. time_resolution Time resolution for the bisecting search if `max_price` is not None. """ def f(max_lead_time): return self.get_quote( sequence, max_lead_time=max_lead_time, with_assembly_plan=with_assembly_plan, ) quote = f(None) if (not quote.accepted) or (quote.price > max_price): return DnaQuote( self, sequence, accepted=False, message="Price over limit even without time limit.", ) step_size = quote.lead_time / 2.0 lead_time = quote.lead_time - step_size best_quote = quote while step_size > time_resolution: quote = f(lead_time) if quote.accepted and (quote.price <= max_price): best_quote = quote lead_time -= step_size else: lead_time += step_size step_size /= 2.0 return best_quote
def prepare_network_on_sequence(self, sequence): _edges, levels = self.compute_supply_graph() for level in levels: for source in level: if hasattr(source, "prepare_on_sequence"): source.prepare_on_sequence(sequence) def dict_description(self): result = { "name": self.name, "operation_type": self.operation_type, "class": self.class_description, "_report_color": self.report_color, "_report_fa_symbol": self.report_fa_symbol, "_report_fa_symbol_plain": self.report_fa_symbol_plain, } result.update(self.additional_dict_description()) return result def additional_dict_description(self): return {}