def v(resistances, r_i, applied_voltages, **kwargs): """Solves matrix equation `gv = i`. Parameters ---------- resistances : ndarray Resistances of crossbar devices. r_i : named tuple of (int or float) Interconnect resistances along the word and bit line segments. applied_voltages : ndarray Applied voltages. Returns ------- ndarray Matrix containing potentials at each of the nodes. """ if r_i.word_line > 0 or r_i.bit_line > 0: g = fill.g(resistances, r_i) i = fill.i(applied_voltages, resistances, r_i) utils.message('Started solving for v.', **kwargs) v_matrix = linalg.spsolve(g.tocsc(), i) utils.message('Solved for v.', **kwargs) # if `num_examples == 1`, it can result in 1D array. if v_matrix.ndim == 1: v_matrix = v_matrix.reshape(v_matrix.shape[0], 1) # if one of the interconnect resistances is zero, only half of the # matrix_v had to be solved. The other half can be filled without # solving because the node voltages are known. if r_i.word_line == 0: new_v_matrix = np.zeros( (2*resistances.size, applied_voltages.shape[1])) new_v_matrix[:resistances.size, ] = np.repeat( applied_voltages, resistances.shape[1], axis=0) new_v_matrix[resistances.size:, ] = v_matrix v_matrix = new_v_matrix if r_i.bit_line == 0: new_v_matrix = np.zeros( (2*resistances.size, applied_voltages.shape[1])) new_v_matrix[:resistances.size, ] = v_matrix v_matrix = new_v_matrix else: # if both interconnect resistances are zero, all node voltages are # known. v_matrix = np.zeros( (2*resistances.size, applied_voltages.shape[1])) v_matrix[:resistances.size, ] = np.repeat( applied_voltages, resistances.shape[1], axis=0) return v_matrix
def currents(extracted_voltages, resistances, r_i, applied_voltages, **kwargs): """Extracts crossbar branch currents in a convenient format. Parameters ---------- extracted_voltages : named tuple Crossbar node voltages. It has fields `word_line` and `bit_line` that contain the potentials at the nodes on the word and bit lines. resistances : ndarray Resistances of crossbar devices. r_i : named tuple of (int or float) Interconnect resistances along the word and bit line segments. applied_voltages : ndarray Applied voltages. **kwargs all_currents : bool, optional If False, only output currents are returned, while all the other ones are set to None. Returns ------- named tuple Crossbar branch currents. Named tuple has fields `output`, `device`, `word_line` and `bit_line` that contain output currents, as well as currents flowing through the devices and interconnect segments of the word and bit lines. """ device_i = device_currents(extracted_voltages, resistances) output_i = output_currents(extracted_voltages, device_i, r_i) if kwargs.get('all_currents'): word_line_i = word_line_currents(extracted_voltages, device_i, r_i, applied_voltages) bit_line_i = bit_line_currents(extracted_voltages, device_i, r_i) utils.message('Extracted currents from all branches in the crossbar.', **kwargs) else: device_i = word_line_i = bit_line_i = None utils.message('Extracted output currents.', **kwargs) extracted_currents = Currents(output_i, device_i, word_line_i, bit_line_i) return extracted_currents
def voltages(v, resistances, **kwargs): """Extracts crossbar node voltages in a convenient format. Parameters ---------- v : ndarray Solution to gv = i in a flattened form. resistances : ndarray Resistances of crossbar devices. Returns ------- named tuple Crossbar node voltages. It has fields `word_line` and `bit_line` that contain the potentials at the nodes on the word and bit lines. """ word_line_v = word_line_voltages(v, resistances) bit_line_v = bit_line_voltages(v, resistances) extracted_voltages = Voltages(word_line_v, bit_line_v) if kwargs.get('node_voltages'): utils.message('Extracted node voltages.', **kwargs) return extracted_voltages
def insulating_interconnect_solution(resistances, applied_voltages, **kwargs): """Extracts solution when all interconnects are perfectly insulating. Parameters ---------- resistances : ndarray Resistances of crossbar devices. applied_voltages : ndarray Applied voltages. **kwargs all_currents : bool, optional If False, only output currents are returned, while all the other ones are set to None. verbose : int If 2, makes sure that warning is displayed. Returns ------- named tuple Branch currents and node voltages of the crossbar. """ extracted_voltages = Voltages(None, None) if kwargs.get('node_voltages'): initial_verbose = kwargs.get('verbose') if initial_verbose == 2: kwargs['verbose'] = 1 utils.message( 'Warning: all interconnects are perfectly insulating! Node ' 'voltages are undefined!', **kwargs) if initial_verbose == 2: kwargs['verbose'] = 2 output_i = np.zeros((applied_voltages.shape[1], resistances.shape[1])) if kwargs.get('all_currents', True): same_i = np.zeros((resistances.shape[0], resistances.shape[1], applied_voltages.shape[1])) same_i = utils.squeeze_third_axis(same_i) device_i = word_line_i = bit_line_i = same_i utils.message('Extracted currents from all branches in the crossbar.', **kwargs) else: device_i = word_line_i = bit_line_i = None utils.message('Extracted output currents.', **kwargs) extracted_currents = Currents(output_i, device_i, word_line_i, bit_line_i) extracted_solution = Solution(extracted_currents, extracted_voltages) return extracted_solution
def compute( applied_voltages, resistances, r_i=None, r_i_word_line=None, r_i_bit_line=None, **kwargs): """Computes branch currents and node voltages of a crossbar. Parameters ---------- applied_voltages : array_like Applied voltages. Voltages must be supplied in an array of shape `m x p`, where `m` is the number of word lines and `p` is the number of examples (sets of voltages applied one by one). resistances : array_like Resistances of crossbar devices. Resistances must be supplied in an array of shape `m x n`, where `n` is the number of bit lines. r_i : int or float, optional Interconnect resistance of the word and bit line segments. If None, `r_i_word_line` and `r_i_bit_line` are used instead. r_i_word_line : int or float, optional Interconnect resistance of the word line segments. r_i_bit_line : int or float, optional Interconnect resistance of the bit line segments. **kwargs node_voltages : bool, optional If False, None is returned instead of node voltages. all_currents : bool, optional If False, only output currents are returned, while all the other ones are set to None. verbose : {1, 2, 0}, optional If 1, all messages are shown. If 2, only warnings are shown. If 0, no messages are shown. show_time : bool, optional If True, includes current time when the messages are printed. gap_size : int, optional Number of whitespace characters to be printed between current time and the message. Returns ------- named tuple Branch currents and node voltages of the crossbar. Field `currents` is a named tuple itself with fields `output`, `device`, `word_line` and `bit_line` and contains output currents, as well as currents flowing through the devices and interconnect segments of the word and bit lines. Field `voltages` is a named tuple itself with fields `word_line` and `bit_line` and contains the voltages at the nodes on the word and bit lines. `currents.output` is an array of shape `p x n`, while all the others are arrays of shape `m x n` if `p == 1`, or arrays of shape `m x n x p` if `p > 1`. """ kwargs.setdefault('node_voltages', True) kwargs.setdefault('all_currents', True) kwargs.setdefault('verbose', 1) kwargs.setdefault('show_time', True) kwargs.setdefault('gap_size', 5) if r_i is not None: r_i_word_line = r_i_bit_line = r_i resistances, applied_voltages = check.crossbar_requirements( resistances, applied_voltages, r_i_word_line, r_i_bit_line) utils.message('Initialising simulation.', **kwargs) solution = computing.extract.solution( resistances, r_i_word_line, r_i_bit_line, applied_voltages, **kwargs) return solution