<commit_before>"""
Evaluates the estimated results of the Segmentation dataset against the
ground truth (human annotated data).
"""

from joblib import Parallel, delayed
import logging
import mir_eval
import os
import pandas as pd
import sys

# Local stuff
import msaf
import msaf.input_output as io
import msaf.algorithms as algorithms
from msaf import jams2
from msaf import utils

def print_results(results):
    """Print all the results.

    Parameters
    ----------
    results: pd.DataFrame
        Dataframe with all the results
    """
    res = results.mean()
    logging.info("Results:\n%s" % res)

def compute_results(ann_inter, est_inter, ann_labels, est_labels, bins,
                    est_file):
    """Compute the results using all the available evaluations.

    Return
    ------
    results : dict
        Contains the results of all the evaluations for the given file.
        Keys are the following:
            track_name  : Name of the track
            ds_name :   Name of the data set
            HitRate_3F  :   F-measure of hit rate at 3 seconds
            HitRate_3P  :   Precision of hit rate at 3 seconds
            HitRate_3R  :   Recall of hit rate at 3 seconds
            HitRate_0.5F  :   F-measure of hit rate at 0.5 seconds
            HitRate_0.5P  :   Precision of hit rate at 0.5 seconds
            HitRate_0.5R  :   Recall of hit rate at 0.5 seconds
            HitRate_t3F  :   F-measure of hit rate at 3 seconds (trimmed)
            HitRate_t3P  :   Precision of hit rate at 3 seconds (trimmed)
            HitRate_t3F  :   Recall of hit rate at 3 seconds (trimmed)
            HitRate_t0.5F  :   F-measure of hit rate at 0.5 seconds (trimmed)
            HitRate_t0.5P  :   Precision of hit rate at 0.5 seconds (trimmed)
            HitRate_t0.5R  :   Recall of hit rate at 0.5 seconds (trimmed)
            DevA2E  :   Median deviation of annotation to estimation
            DevE2A  :   Median deviation of estimation to annotation
            D   :   Information gain
            PWF : F-measure of pair-wise frame clustering
            PWP : Precision of pair-wise frame clustering
            PWR : Recall of pair-wise frame clustering
            Sf  : F-measure normalized entropy score
            So  : Oversegmentation normalized entropy score
            Su  : Undersegmentation normalized entropy score
    """
    logging.info("Evaluating %s" % os.path.basename(est_file))
    res = {}

    ### Boundaries ###
    # Hit Rate
    res["HitRate_3P"], res["HitRate_3R"], res["HitRate_3F"] = \
        mir_eval.segment.detection(ann_inter, est_inter, window=3, trim=False)
    res["HitRate_0.5P"], res["HitRate_0.5R"], res["HitRate_0.5F"] = \
        mir_eval.segment.detection(ann_inter, est_inter, window=.5, trim=False)
    res["HitRate_t3P"], res["HitRate_t3R"], res["HitRate_t3F"] = \
        mir_eval.segment.detection(ann_inter, est_inter, window=3, trim=True)
    res["HitRate_t0.5P"], res["HitRate_t0.5R"], res["HitRate_t0.5F"] = \
        mir_eval.segment.detection(ann_inter, est_inter, window=.5, trim=True)

    # Information gain
    res["D"] = compute_information_gain(ann_inter, est_inter, est_file,
                                        bins=bins)

    # Median Deviations
    res["DevR2E"], res["DevE2R"] = mir_eval.segment.deviation(
        ann_inter, est_inter, trim=False)
    res["DevtR2E"], res["DevtE2R"] = mir_eval.segment.deviation(
        ann_inter, est_inter, trim=True)

    ### Labels ###
    if est_labels is not None and len(est_labels) != 0:
        try:
            # Align labels with intervals
            ann_labels = list(ann_labels)
            est_labels = list(est_labels)
            ann_inter, ann_labels = mir_eval.util.adjust_intervals(ann_inter,
                                                                ann_labels)
            est_inter, est_labels = mir_eval.util.adjust_intervals(
                est_inter, est_labels, t_min=0, t_max=ann_inter.max())

            # Pair-wise frame clustering
            res["PWP"], res["PWR"], res["PWF"] = mir_eval.segment.pairwise(
                ann_inter, ann_labels, est_inter, est_labels)

            # Normalized Conditional Entropies
            res["So"], res["Su"], res["Sf"] = mir_eval.segment.nce(
                ann_inter, ann_labels, est_inter, est_labels)
        except:
            logging.warning("Labeling evaluation failed in file: %s" %
                            est_file)
            return {}

    # Names
    base = os.path.basename(est_file)
    res["track_id"] = base[:-5]
    res["ds_name"] = base.split("_")[0]

    return res

def compute_gt_results(est_file, ref_file, boundaries_id, labels_id, config,
                       bins=251):
    """Computes the results by using the ground truth dataset identified by
    the annotator parameter.

    Return
    ------
    results : dict
        Dictionary of the results (see function compute_results).
    """

    # Get the ds_prefix
    ds_prefix = os.path.basename(est_file).split("_")[0]

    try:
        ref_inter, ref_labels = jams2.converters.load_jams_range(
            ref_file, "sections", annotator=0,
            context=msaf.prefix_dict[ds_prefix])
    except:
        logging.warning("No references for file: %s" % ref_file)
        return {}

    # Read estimations with correct configuration
    est_inter, est_labels = io.read_estimations(est_file, boundaries_id,
                                                labels_id, **config)

    if len(est_inter) == 0:
        logging.warning("No estimations for file: %s" % est_file)
        return {}

    # Compute the results and return
    return compute_results(ref_inter, est_inter, ref_labels, est_labels,
                           bins, est_file)

def compute_information_gain(ann_inter, est_inter, est_file, bins):
    """Computes the information gain of the est_file from the annotated
    intervals and the estimated intervals."""
    ann_times = utils.intervals_to_times(ann_inter)
    est_times = utils.intervals_to_times(est_inter)
    try:
        D = mir_eval.beat.information_gain(ann_times, est_times, bins=bins)
    except:
        logging.warning("Couldn't compute the Information Gain for file "
                        "%s" % est_file)
        D = 0
    return D

def process_track(file_struct, boundaries_id, labels_id, config):
    """Processes a single track."""

    est_file = file_struct.est_file
    ref_file = file_struct.ref_file

    # Sanity check
    assert os.path.basename(est_file)[:-4] == \
        os.path.basename(ref_file)[:-4], "File names are different %s --- %s" \
        % (os.path.basename(est_file)[:-4], os.path.basename(ref_file)[:-4])

    try:
        one_res = compute_gt_results(est_file, ref_file, boundaries_id,
                                     labels_id, config)
    except:
        logging.warning("Could not compute evaluations for %s. Error: %s" %
                        (est_file, sys.exc_info()[1]))
        one_res = []

    return one_res

def get_results_file_name(boundaries_id, labels_id, config, ds_name):
    """Based on the config and the dataset, get the file name to store the
    results."""
    if ds_name == "*":
        ds_name = "All"
    utils.ensure_dir(msaf.results_dir)
    file_name = os.path.join(msaf.results_dir, "results_%s" % ds_name)
    file_name += "_boundsE%s_labelsE%s" % (boundaries_id, labels_id)
    sorted_keys = sorted(config.keys(),
                         cmp=lambda x, y: cmp(x.lower(), y.lower()))
    for key in sorted_keys:
        file_name += "_%sE%s" % (key, str(config[key]).replace("/", "_"))
    return file_name + msaf.results_ext

def process(in_path, boundaries_id, labels_id=None, ds_name="*",
            annot_beats=False, framesync=False, feature="hpcp", save=False,
            n_jobs=4, config=None):
    """Main process.

    Parameters
    ----------
    in_path : str
        Path to the dataset root folder.
    boundaries_id : str
        Boundaries algorithm identifier (e.g. siplca, cnmf)
    labels_id : str
        Labels algorithm identifier (e.g. siplca, cnmf)
    ds_name : str
        Name of the dataset to be evaluated (e.g. SALAMI). * stands for all.
    annot_beats : boolean
        Whether to use the annotated beats or not.
    annot_bounds : boolean
        Whether to use the annotated bounds or not.
    save: boolean
        Whether to save the results into the SQLite database.
    params : dict
        Additional parameters (e.g. features)

    Return
    ------
    results : pd.DataFrame
        DataFrame containing the evaluations for each file.
    """

    # Set up configuration based on algorithms parameters
    if config is None:
        config = io.get_configuration(feature, annot_beats, framesync,
                                      boundaries_id, labels_id)

    # Get out file in case we want to save results
    out_file = get_results_file_name(boundaries_id, labels_id, config, ds_name)

    # If out_file already exists, do not compute new results
    if os.path.exists(out_file):
        logging.info("Results already exists, reading from file %s" % out_file)
        results = pd.read_csv(out_file)
        print_results(results)
        return results

    # Get files
    file_structs = io.get_dataset_files(in_path, ds_name)

    logging.info("Evaluating %d tracks..." % len(file_structs))

    # All evaluations
    results = pd.DataFrame()

    # Evaluate in parallel
    evals = Parallel(n_jobs=n_jobs)(delayed(process_track)(
        file_struct, boundaries_id, labels_id, config)
        for file_struct in file_structs[:])

    # Aggregat evaluations in pandas format
    for e in evals:
        if e != []:
            results = results.append(e, ignore_index=True)
    logging.info("%d tracks analyzed" % len(results))

    # Print results
    print_results(results)

    # Save all results
    if save:
        logging.info("Writing average results in %s" % out_file)
        results.to_csv(out_file)

    return results
<commit_msg>Fixed dictionary prefix to evaluate the Sargon dataset<commit_after>"""
Evaluates the estimated results of the Segmentation dataset against the
ground truth (human annotated data).
"""

from joblib import Parallel, delayed
import logging
import mir_eval
import os
import pandas as pd
import sys

# Local stuff
import msaf
import msaf.input_output as io
import msaf.algorithms as algorithms
from msaf import jams2
from msaf import utils

def print_results(results):
    """Print all the results.

    Parameters
    ----------
    results: pd.DataFrame
        Dataframe with all the results
    """
    res = results.mean()
    logging.info("Results:\n%s" % res)

def compute_results(ann_inter, est_inter, ann_labels, est_labels, bins,
                    est_file):
    """Compute the results using all the available evaluations.

    Return
    ------
    results : dict
        Contains the results of all the evaluations for the given file.
        Keys are the following:
            track_name  : Name of the track
            ds_name :   Name of the data set
            HitRate_3F  :   F-measure of hit rate at 3 seconds
            HitRate_3P  :   Precision of hit rate at 3 seconds
            HitRate_3R  :   Recall of hit rate at 3 seconds
            HitRate_0.5F  :   F-measure of hit rate at 0.5 seconds
            HitRate_0.5P  :   Precision of hit rate at 0.5 seconds
            HitRate_0.5R  :   Recall of hit rate at 0.5 seconds
            HitRate_t3F  :   F-measure of hit rate at 3 seconds (trimmed)
            HitRate_t3P  :   Precision of hit rate at 3 seconds (trimmed)
            HitRate_t3F  :   Recall of hit rate at 3 seconds (trimmed)
            HitRate_t0.5F  :   F-measure of hit rate at 0.5 seconds (trimmed)
            HitRate_t0.5P  :   Precision of hit rate at 0.5 seconds (trimmed)
            HitRate_t0.5R  :   Recall of hit rate at 0.5 seconds (trimmed)
            DevA2E  :   Median deviation of annotation to estimation
            DevE2A  :   Median deviation of estimation to annotation
            D   :   Information gain
            PWF : F-measure of pair-wise frame clustering
            PWP : Precision of pair-wise frame clustering
            PWR : Recall of pair-wise frame clustering
            Sf  : F-measure normalized entropy score
            So  : Oversegmentation normalized entropy score
            Su  : Undersegmentation normalized entropy score
    """
    logging.info("Evaluating %s" % os.path.basename(est_file))
    res = {}

    ### Boundaries ###
    # Hit Rate
    res["HitRate_3P"], res["HitRate_3R"], res["HitRate_3F"] = \
        mir_eval.segment.detection(ann_inter, est_inter, window=3, trim=False)
    res["HitRate_0.5P"], res["HitRate_0.5R"], res["HitRate_0.5F"] = \
        mir_eval.segment.detection(ann_inter, est_inter, window=.5, trim=False)
    res["HitRate_t3P"], res["HitRate_t3R"], res["HitRate_t3F"] = \
        mir_eval.segment.detection(ann_inter, est_inter, window=3, trim=True)
    res["HitRate_t0.5P"], res["HitRate_t0.5R"], res["HitRate_t0.5F"] = \
        mir_eval.segment.detection(ann_inter, est_inter, window=.5, trim=True)

    # Information gain
    res["D"] = compute_information_gain(ann_inter, est_inter, est_file,
                                        bins=bins)

    # Median Deviations
    res["DevR2E"], res["DevE2R"] = mir_eval.segment.deviation(
        ann_inter, est_inter, trim=False)
    res["DevtR2E"], res["DevtE2R"] = mir_eval.segment.deviation(
        ann_inter, est_inter, trim=True)

    ### Labels ###
    if est_labels is not None and len(est_labels) != 0:
        try:
            # Align labels with intervals
            ann_labels = list(ann_labels)
            est_labels = list(est_labels)
            ann_inter, ann_labels = mir_eval.util.adjust_intervals(ann_inter,
                                                                ann_labels)
            est_inter, est_labels = mir_eval.util.adjust_intervals(
                est_inter, est_labels, t_min=0, t_max=ann_inter.max())

            # Pair-wise frame clustering
            res["PWP"], res["PWR"], res["PWF"] = mir_eval.segment.pairwise(
                ann_inter, ann_labels, est_inter, est_labels)

            # Normalized Conditional Entropies
            res["So"], res["Su"], res["Sf"] = mir_eval.segment.nce(
                ann_inter, ann_labels, est_inter, est_labels)
        except:
            logging.warning("Labeling evaluation failed in file: %s" %
                            est_file)
            return {}

    # Names
    base = os.path.basename(est_file)
    res["track_id"] = base[:-5]
    res["ds_name"] = base.split("_")[0]

    return res

def compute_gt_results(est_file, ref_file, boundaries_id, labels_id, config,
                       bins=251):
    """Computes the results by using the ground truth dataset identified by
    the annotator parameter.

    Return
    ------
    results : dict
        Dictionary of the results (see function compute_results).
    """

    # Get the ds_prefix
    ds_prefix = os.path.basename(est_file).split("_")[0]

    # Get context
    if ds_prefix in msaf.prefix_dict.keys():
        context = msaf.prefix_dict[ds_prefix]
    else:
        context = "function"

    try:
        ref_inter, ref_labels = jams2.converters.load_jams_range(
            ref_file, "sections", annotator=0, context=context)
    except:
        logging.warning("No references for file: %s" % ref_file)
        return {}

    # Read estimations with correct configuration
    est_inter, est_labels = io.read_estimations(est_file, boundaries_id,
                                                labels_id, **config)

    if len(est_inter) == 0:
        logging.warning("No estimations for file: %s" % est_file)
        return {}

    # Compute the results and return
    return compute_results(ref_inter, est_inter, ref_labels, est_labels,
                           bins, est_file)

def compute_information_gain(ann_inter, est_inter, est_file, bins):
    """Computes the information gain of the est_file from the annotated
    intervals and the estimated intervals."""
    ann_times = utils.intervals_to_times(ann_inter)
    est_times = utils.intervals_to_times(est_inter)
    try:
        D = mir_eval.beat.information_gain(ann_times, est_times, bins=bins)
    except:
        logging.warning("Couldn't compute the Information Gain for file "
                        "%s" % est_file)
        D = 0
    return D

def process_track(file_struct, boundaries_id, labels_id, config):
    """Processes a single track."""

    est_file = file_struct.est_file
    ref_file = file_struct.ref_file

    # Sanity check
    assert os.path.basename(est_file)[:-4] == \
        os.path.basename(ref_file)[:-4], "File names are different %s --- %s" \
        % (os.path.basename(est_file)[:-4], os.path.basename(ref_file)[:-4])

    try:
        one_res = compute_gt_results(est_file, ref_file, boundaries_id,
                                     labels_id, config)
    except:
        logging.warning("Could not compute evaluations for %s. Error: %s" %
                        (est_file, sys.exc_info()[1]))
        one_res = []

    return one_res

def get_results_file_name(boundaries_id, labels_id, config, ds_name):
    """Based on the config and the dataset, get the file name to store the
    results."""
    if ds_name == "*":
        ds_name = "All"
    utils.ensure_dir(msaf.results_dir)
    file_name = os.path.join(msaf.results_dir, "results_%s" % ds_name)
    file_name += "_boundsE%s_labelsE%s" % (boundaries_id, labels_id)
    sorted_keys = sorted(config.keys(),
                         cmp=lambda x, y: cmp(x.lower(), y.lower()))
    for key in sorted_keys:
        file_name += "_%sE%s" % (key, str(config[key]).replace("/", "_"))
    return file_name + msaf.results_ext

def process(in_path, boundaries_id, labels_id=None, ds_name="*",
            annot_beats=False, framesync=False, feature="hpcp", save=False,
            n_jobs=4, config=None):
    """Main process.

    Parameters
    ----------
    in_path : str
        Path to the dataset root folder.
    boundaries_id : str
        Boundaries algorithm identifier (e.g. siplca, cnmf)
    labels_id : str
        Labels algorithm identifier (e.g. siplca, cnmf)
    ds_name : str
        Name of the dataset to be evaluated (e.g. SALAMI). * stands for all.
    annot_beats : boolean
        Whether to use the annotated beats or not.
    annot_bounds : boolean
        Whether to use the annotated bounds or not.
    save: boolean
        Whether to save the results into the SQLite database.
    params : dict
        Additional parameters (e.g. features)

    Return
    ------
    results : pd.DataFrame
        DataFrame containing the evaluations for each file.
    """

    # Set up configuration based on algorithms parameters
    if config is None:
        config = io.get_configuration(feature, annot_beats, framesync,
                                      boundaries_id, labels_id)

    # Get out file in case we want to save results
    out_file = get_results_file_name(boundaries_id, labels_id, config, ds_name)

    # If out_file already exists, do not compute new results
    if os.path.exists(out_file):
        logging.info("Results already exists, reading from file %s" % out_file)
        results = pd.read_csv(out_file)
        print_results(results)
        return results

    # Get files
    file_structs = io.get_dataset_files(in_path, ds_name)

    logging.info("Evaluating %d tracks..." % len(file_structs))

    # All evaluations
    results = pd.DataFrame()

    # Evaluate in parallel
    evals = Parallel(n_jobs=n_jobs)(delayed(process_track)(
        file_struct, boundaries_id, labels_id, config)
        for file_struct in file_structs[:])

    # Aggregat evaluations in pandas format
    for e in evals:
        if e != []:
            results = results.append(e, ignore_index=True)
    logging.info("%d tracks analyzed" % len(results))

    # Print results
    print_results(results)

    # Save all results
    if save:
        logging.info("Writing average results in %s" % out_file)
        results.to_csv(out_file)

    return results
<|endoftext|>


<commit_before>
"""Implementation of a different phone-loop structure as FST that can
be used to discover acoustic units."""

import abc
import tempfile
import numpy as np
import pywrapfst as fst

class DecodableGraph(metaclass=abc.ABCMeta):

    def forward(self):
        pass

    def backward(self):
        pass

    def updatePosterior(self, stats):
        """Update the parameters of the posterior distribution according
        to the accumulated statistics.

        Parameters
        ----------
        stats : object
            Accumulated statistics.

        """
        pass

class UnigramDecodableGraph(DecodableGraph):

    @property
    def graph(self):
        return self._graph

    # ------------------------------------------------------------------
    # We override the pickling behavior of the object to be able to deal
    # with OpenFst component. This is inefficient as we have to write
    # the object on the disk but it avoid to modify the OpenFst API.

    def __getstate__(self):
        state = self.__dict__.copy()

        out = tempfile.NamedTemporaryFile()
        state['_graph'].write(out.name)
        with open(out.name, 'rb') as f:
            state['_graph'] = f.read()

        out = tempfile.NamedTemporaryFile()
        state['_r_graph'].write(out.name)
        with open(out.name, 'rb') as f:
            state['_r_graph'] = f.read()

        return state

    def __setstate__(self, newstate):
        out = tempfile.NamedTemporaryFile()
        with open(out.name, 'wb') as f:
            f.write(newstate['_graph'])
        newstate['_graph'] = fst.Fst.read(out.name)

        out = tempfile.NamedTemporaryFile()
        with open(out.name, 'wb') as f:
            f.write(newstate['_r_graph'])
        newstate['_r_graph'] = fst.Fst.read(out.name)

        self.__dict__.update(newstate)

    # ------------------------------------------------------------------

    def __init__(self, nunits, nstates):
        self.nunits = nunits
        self.nstates = nstates

        # Create the fst.
        self._graph = fst.Fst('log')

        # Set the initial/final state.
        self._start_state = self._graph.add_state()
        self._graph.set_start(self._start_state)
        self._end_state = self._graph.add_state()
        self._graph.set_final(self._end_state)

        # Create the states of the graphs.
        for i in range(nunits * nstates):
            self._graph.add_state()

        # Define the possible initial and final states.
        self._init_states = [self._start_state + 2]
        self._final_states = [self._start_state + nstates + 1]
        for i in range(1, nunits):
            self._final_states.append(self._final_states[i - 1] + nstates)
            self._init_states.append(self._final_states[-1] - nstates + 1)

        # Create the mapping state -> index that will be used during the
        # forward-backward algorithm.
        self._state_index = {}
        for i in range(nunits * nstates):
            self._state_index[i + 2] = i

        # Connect the graph's states.
        self.__connectStates()

        # For the backward recursion we need the reversed graph.
        self._r_graph = fst.reverse(self._graph, require_superinitial=False)

    def __connectStates(self):
        # Weight shared for all HMM transitions.
        weight = fst.Weight('log', -np.log(.5))

        # Connect all the initial states to the starting state.
        for state in self._init_states:
            arc = fst.Arc(state, state, weight, state)
            self._graph.add_arc(self._start_state, arc)

        for state in self._final_states:
            arc = fst.Arc(0, 0, fst.Weight.One('log'), self._end_state)
            self._graph.add_arc(state, arc)

        # Connect all the final states to the initial states to complete
        # the loop.
        for final_state in self._final_states:
            for init_state in self._init_states:
                arc = fst.Arc(init_state, init_state, fst.Weight.One('log'),
                              init_state)
                self._graph.add_arc(final_state, arc)

        # HMM connections.
        for init_state in self._init_states:
            for state in range(init_state, init_state + self.nstates):
                # Self loops.
                arc = fst.Arc(state, state, weight, state)
                self._graph.add_arc(state, arc)

                # State to state transition.
                if state not in self._final_states:
                    next_state = state + 1
                    arc = fst.Arc(next_state, next_state, weight, next_state)
                    self._graph.add_arc(state, arc)

    def __distanceToFinalState(self, state):
        return ((state - 1) % self.nstates) + 1

    def __distanceToInitialState(self, state):
        return self.nstates - ((state - 1) % self.nstates)

    def __consumeEpsilons(self, graph, arc):
        if arc.ilabel == 0:
            arcs = []
            for new_arc in graph.arcs(arc.nextstate):
                arcs += self.__consumeEpsilons(graph, new_arc)
            return arcs
        else:
            return [arc]

    def __stepForward(self, state, frame_index, log_alphas, llhs,
                      active_states):
        # Forward value up to the current state.
        if frame_index == 0:
            log_alpha = fst.Weight.One('log')
        else:
            state_idx = self._state_index[state]
            log_alpha = log_alphas[frame_index - 1, state_idx]

        # Propagate the weight for each outgoing arcs.
        for arc in self._graph.arcs(state):
            # Make sure the path is a valid.
            if arc.nextstate == self._end_state:
                continue
            remaining_frame = len(llhs) - frame_index
            if self.__distanceToFinalState(arc.nextstate) > remaining_frame:
                continue

            # Index of the state we propagate the forward recursion.
            next_state_idx = self._state_index[arc.nextstate]

            # Convert the acoustic weight into OpenFst weight.
            ac_weight = fst.Weight('log', -llhs[frame_index, next_state_idx])

            # Weight to add for this state.
            weight = fst.times(arc.weight, log_alpha)
            weight = fst.times(weight, ac_weight)

            if log_alphas[frame_index, next_state_idx] is None:
                log_alphas[frame_index, next_state_idx] = weight
            else:
                current_weight = log_alphas[frame_index, next_state_idx]
                log_alphas[frame_index, next_state_idx] = \
                    fst.plus(current_weight, weight)

            # Add the state to the active state set.
            active_states.add(arc.nextstate)

    def __stepBackward(self, state, frame_index, log_betas, llhs,
                       active_states):
        # Index of the current state.
        state_idx = self._state_index[state]

        # Backward value up to the current state.
        log_beta = log_betas[frame_index, state_idx]

        # Propagate the weight for each outgoing arcs.
        for arc in self._r_graph.arcs(state):
            assert arc.ilabel != 0, "Oops !"

            # Make sure the path is a valid.
            if arc.nextstate == self._start_state:
                continue
            remaining_frame = frame_index
            if self.__distanceToInitialState(arc.nextstate) > remaining_frame:
                continue

            # Index of the state we propagate the backward recursion.
            next_state_idx = self._state_index[arc.nextstate]

            # Convert the acoustic weight into OpenFst weight.
            ac_weight = \
                fst.Weight('log', -llhs[frame_index, state_idx])

            # Weight to add for this state.
            weight = fst.times(arc.weight, log_beta)
            weight = fst.times(weight, ac_weight)

            if log_betas[frame_index - 1, next_state_idx] is None:
                log_betas[frame_index - 1, next_state_idx] = weight
            else:
                current_weight = log_betas[frame_index - 1, next_state_idx]
                log_betas[frame_index - 1, next_state_idx] = \
                    fst.plus(current_weight, weight)

            # Add the state to the active state set.
            active_states.add(arc.nextstate)

    def forward(self, llhs):
        """Forward recursion given the log emission probabilities and
        the HMM model.

        Parameters
        ----------
        llhs : numpy.ndarray
            Log of the emission probabilites with shape (N x K) where N
            is the number of frame in the sequence and K is the number
            of state in the HMM model.

        Returns
        -------
        log_alphas : numpy.ndarray
            The log alphas values of the recursions.

        """
        # Allocate a matrix where we will store the results of the
        # forward recursion.
        log_alphas = np.empty_like(llhs, dtype=object)

        # Starting point of the forward recursion.
        active_states = set([self._start_state])

        # Current frame index.
        frame_index = 0

        # Forward recursion.
        while frame_index < len(llhs):
            # Current state from which to expand the forward recursion.
            states = list(active_states)

            for state in states:
                active_states.remove(state)
                self.__stepForward(state, frame_index, log_alphas, llhs,
                                   active_states)
            frame_index += 1

        # For debugging.
        retval = np.empty_like(log_alphas, dtype=float)
        for i in range(log_alphas.shape[0]):
            for j in range(log_alphas.shape[1]):
                if log_alphas[i, j] is None:
                    retval[i, j] = float('-inf')
                else:
                    retval[i, j] = -float(log_alphas[i, j].string)

        return retval

    def backward(self, llhs):
        """Backward recursion given the log emission probabilities and
        the HMM model.

        Parameters
        ----------
        llhs : numpy.ndarray
            Log of the emission probabilites with shape (N x K) where N
            is the number of frame in the sequence and K is the number
            of state in the HMM model.

        Returns
        -------
        log_alphas : numpy.ndarray
            The log alphas values of the recursions.

        """
        # Allocate a matrix where we will store the results of the
        # forward recursion.
        log_betas = np.empty_like(llhs, dtype=object)

        # Initialize the recurstion.
        for state in self._final_states:
            state_idx = self._state_index[state]
            log_betas[-1, state_idx] = fst.Weight.One('log')

        # Starting point of the backward recursion.
        active_states = set(self._final_states)

        # Current frame index.
        frame_index = len(llhs) - 1

        # Backward recursion.
        while frame_index >= 0:
            print('frame_index:', frame_index)
            # Current state from which to expand the backward recursion.
            states = list(active_states)
            for state in states:
                active_states.remove(state)
                self.__stepBackward(state, frame_index, log_betas, llhs,
                                    active_states)
            frame_index -= 1

        # For debugging.
        retval = np.empty_like(log_betas, dtype=float)
        for i in range(log_betas.shape[0]):
            for j in range(log_betas.shape[1]):
                if log_betas[i, j] is None:
                    retval[i, j] = float('-inf')
                else:
                    retval[i, j] = -float(log_betas[i, j].string)

        return retval
<commit_msg>Removed unused function.<commit_after>
"""Implementation of a different phone-loop structure as FST that can
be used to discover acoustic units."""

import abc
import tempfile
import numpy as np
import pywrapfst as fst

class DecodableGraph(metaclass=abc.ABCMeta):

    def forward(self):
        pass

    def backward(self):
        pass

    def updatePosterior(self, stats):
        """Update the parameters of the posterior distribution according
        to the accumulated statistics.

        Parameters
        ----------
        stats : object
            Accumulated statistics.

        """
        pass

class UnigramDecodableGraph(DecodableGraph):

    @property
    def graph(self):
        return self._graph

    # ------------------------------------------------------------------
    # We override the pickling behavior of the object to be able to deal
    # with the OpenFst component. This is inefficient as we have to
    # write the object on the disk but it avoid to modify the OpenFst
    # API.

    def __getstate__(self):
        state = self.__dict__.copy()

        out = tempfile.NamedTemporaryFile()
        state['_graph'].write(out.name)
        with open(out.name, 'rb') as f:
            state['_graph'] = f.read()

        out = tempfile.NamedTemporaryFile()
        state['_r_graph'].write(out.name)
        with open(out.name, 'rb') as f:
            state['_r_graph'] = f.read()

        return state

    def __setstate__(self, newstate):
        out = tempfile.NamedTemporaryFile()
        with open(out.name, 'wb') as f:
            f.write(newstate['_graph'])
        newstate['_graph'] = fst.Fst.read(out.name)

        out = tempfile.NamedTemporaryFile()
        with open(out.name, 'wb') as f:
            f.write(newstate['_r_graph'])
        newstate['_r_graph'] = fst.Fst.read(out.name)

        self.__dict__.update(newstate)

    # ------------------------------------------------------------------

    def __init__(self, nunits, nstates):
        self.nunits = nunits
        self.nstates = nstates

        # Create the fst.
        self._graph = fst.Fst('log')

        # Set the initial/final state.
        self._start_state = self._graph.add_state()
        self._graph.set_start(self._start_state)
        self._end_state = self._graph.add_state()
        self._graph.set_final(self._end_state)

        # Create the states of the graphs.
        for i in range(nunits * nstates):
            self._graph.add_state()

        # Define the possible initial and final states.
        self._init_states = [self._start_state + 2]
        self._final_states = [self._start_state + nstates + 1]
        for i in range(1, nunits):
            self._final_states.append(self._final_states[i - 1] + nstates)
            self._init_states.append(self._final_states[-1] - nstates + 1)

        # Create the mapping state -> index that will be used during the
        # forward-backward algorithm.
        self._state_index = {}
        for i in range(nunits * nstates):
            self._state_index[i + 2] = i

        # Connect the graph's states.
        self.__connectStates()

        # For the backward recursion we need the reversed graph.
        self._r_graph = fst.reverse(self._graph, require_superinitial=False)

    def __connectStates(self):
        # Weight shared for all HMM transitions.
        weight = fst.Weight('log', -np.log(.5))

        # Connect all the initial states to the starting state.
        for state in self._init_states:
            arc = fst.Arc(state, state, weight, state)
            self._graph.add_arc(self._start_state, arc)

        for state in self._final_states:
            arc = fst.Arc(0, 0, fst.Weight.One('log'), self._end_state)
            self._graph.add_arc(state, arc)

        # Connect all the final states to the initial states to complete
        # the loop.
        for final_state in self._final_states:
            for init_state in self._init_states:
                arc = fst.Arc(init_state, init_state, fst.Weight.One('log'),
                              init_state)
                self._graph.add_arc(final_state, arc)

        # HMM connections.
        for init_state in self._init_states:
            for state in range(init_state, init_state + self.nstates):
                # Self loops.
                arc = fst.Arc(state, state, weight, state)
                self._graph.add_arc(state, arc)

                # State to state transition.
                if state not in self._final_states:
                    next_state = state + 1
                    arc = fst.Arc(next_state, next_state, weight, next_state)
                    self._graph.add_arc(state, arc)

    def __distanceToFinalState(self, state):
        return ((state - 1) % self.nstates) + 1

    def __distanceToInitialState(self, state):
        return self.nstates - ((state - 1) % self.nstates)

    def __stepForward(self, state, frame_index, log_alphas, llhs,
                      active_states):
        # Forward value up to the current state.
        if frame_index == 0:
            log_alpha = fst.Weight.One('log')
        else:
            state_idx = self._state_index[state]
            log_alpha = log_alphas[frame_index - 1, state_idx]

        # Propagate the weight for each outgoing arcs.
        for arc in self._graph.arcs(state):
            # Make sure the path is a valid.
            if arc.nextstate == self._end_state:
                continue
            remaining_frame = len(llhs) - frame_index
            if self.__distanceToFinalState(arc.nextstate) > remaining_frame:
                continue

            # Index of the state we propagate the forward recursion.
            next_state_idx = self._state_index[arc.nextstate]

            # Convert the acoustic weight into OpenFst weight.
            ac_weight = fst.Weight('log', -llhs[frame_index, next_state_idx])

            # Weight to add for this state.
            weight = fst.times(arc.weight, log_alpha)
            weight = fst.times(weight, ac_weight)

            if log_alphas[frame_index, next_state_idx] is None:
                log_alphas[frame_index, next_state_idx] = weight
            else:
                current_weight = log_alphas[frame_index, next_state_idx]
                log_alphas[frame_index, next_state_idx] = \
                    fst.plus(current_weight, weight)

            # Add the state to the active state set.
            active_states.add(arc.nextstate)

    def __stepBackward(self, state, frame_index, log_betas, llhs,
                       active_states):
        # Index of the current state.
        state_idx = self._state_index[state]

        # Backward value up to the current state.
        log_beta = log_betas[frame_index, state_idx]

        # Propagate the weight for each outgoing arcs.
        for arc in self._r_graph.arcs(state):
            assert arc.ilabel != 0, "Oops !"

            # Make sure the path is a valid.
            if arc.nextstate == self._start_state:
                continue
            remaining_frame = frame_index
            if self.__distanceToInitialState(arc.nextstate) > remaining_frame:
                continue

            # Index of the state we propagate the backward recursion.
            next_state_idx = self._state_index[arc.nextstate]

            # Convert the acoustic weight into OpenFst weight.
            ac_weight = \
                fst.Weight('log', -llhs[frame_index, state_idx])

            # Weight to add for this state.
            weight = fst.times(arc.weight, log_beta)
            weight = fst.times(weight, ac_weight)

            if log_betas[frame_index - 1, next_state_idx] is None:
                log_betas[frame_index - 1, next_state_idx] = weight
            else:
                current_weight = log_betas[frame_index - 1, next_state_idx]
                log_betas[frame_index - 1, next_state_idx] = \
                    fst.plus(current_weight, weight)

            # Add the state to the active state set.
            active_states.add(arc.nextstate)

    def forward(self, llhs):
        """Forward recursion given the log emission probabilities and
        the HMM model.

        Parameters
        ----------
        llhs : numpy.ndarray
            Log of the emission probabilites with shape (N x K) where N
            is the number of frame in the sequence and K is the number
            of state in the HMM model.

        Returns
        -------
        log_alphas : numpy.ndarray
            The log alphas values of the recursions.

        """
        # Allocate a matrix where we will store the results of the
        # forward recursion.
        log_alphas = np.empty_like(llhs, dtype=object)

        # Starting point of the forward recursion.
        active_states = set([self._start_state])

        # Current frame index.
        frame_index = 0

        # Forward recursion.
        while frame_index < len(llhs):
            # Current state from which to expand the forward recursion.
            states = list(active_states)

            for state in states:
                active_states.remove(state)
                self.__stepForward(state, frame_index, log_alphas, llhs,
                                   active_states)
            frame_index += 1

        # For debugging.
        retval = np.empty_like(log_alphas, dtype=float)
        for i in range(log_alphas.shape[0]):
            for j in range(log_alphas.shape[1]):
                if log_alphas[i, j] is None:
                    retval[i, j] = float('-inf')
                else:
                    retval[i, j] = -float(log_alphas[i, j].string)

        return retval

    def backward(self, llhs):
        """Backward recursion given the log emission probabilities and
        the HMM model.

        Parameters
        ----------
        llhs : numpy.ndarray
            Log of the emission probabilites with shape (N x K) where N
            is the number of frame in the sequence and K is the number
            of state in the HMM model.

        Returns
        -------
        log_alphas : numpy.ndarray
            The log alphas values of the recursions.

        """
        # Allocate a matrix where we will store the results of the
        # forward recursion.
        log_betas = np.empty_like(llhs, dtype=object)

        # Initialize the recurstion.
        for state in self._final_states:
            state_idx = self._state_index[state]
            log_betas[-1, state_idx] = fst.Weight.One('log')

        # Starting point of the backward recursion.
        active_states = set(self._final_states)

        # Current frame index.
        frame_index = len(llhs) - 1

        # Backward recursion.
        while frame_index >= 0:
            print('frame_index:', frame_index)
            # Current state from which to expand the backward recursion.
            states = list(active_states)
            for state in states:
                active_states.remove(state)
                self.__stepBackward(state, frame_index, log_betas, llhs,
                                    active_states)
            frame_index -= 1

        # For debugging.
        retval = np.empty_like(log_betas, dtype=float)
        for i in range(log_betas.shape[0]):
            for j in range(log_betas.shape[1]):
                if log_betas[i, j] is None:
                    retval[i, j] = float('-inf')
                else:
                    retval[i, j] = -float(log_betas[i, j].string)

        return retval
<|endoftext|>


<commit_before>from numpy import *

class PVReadSparse(object):
   """A class to read PetaVision sparse activity files"""

   def __init__(self, filename):
      """Constructor: Open file and read in file metadata into params"""

      self.open(filename)
      self.read_params()
      self.time = 0
      self.timestep = 0

   # end __init__

   def open(self, filename):
      """Open given filename"""
      self.filename = filename
      self.file = open(filename, mode='rb')
   # end open

   def next_record(self):
      """Read the next record and return an ndarray"""
      self.time = fromfile(self.file, 'd', 1) [0]
      numItems = fromfile(self.file, 'i', 1) [0]
      if (numItems > 0):
         activity = fromfile(self.file, 'i', numItems)
      else:
         activity = []
      self.timestep += 1
      return activity
   # end next

   def read_params(self):
      """Read the file metadata parameters"""
      filepos = self.file.tell()
      self.numParams = fromfile(self.file, 'i', 2) [1]
      self.file.seek(filepos)
      self.params = fromfile(self.file, 'i', self.numParams)

      self.nx,self.ny,self.nf = self.params[3:6]
      self.nxProcs,self.nyProcs = self.params[5:7]
   # end read_params

   def rewind(self):
      """Rewind the file to the start of the data (just past metadata)"""
      self.file.seek(4 * (self.numParams + 1))
   # end rewind

# end class PVReadSparse

<commit_msg>A method to compute the averaged firing rate of the neurons was added.<commit_after>from numpy import *

class PVReadSparse(object):
   """A class to read PetaVision sparse activity files"""

   def __init__(self, filename):
      """Constructor: Open file and read in file metadata into params"""

      self.open(filename)
      self.read_params()
      self.time = 0
      self.timestep = 0
   # end __init__

   def open(self, filename):
      """Open given filename"""
      self.filename = filename
      self.file = open(filename, mode='rb')
   # end open

   def next_record(self):
      """Read the next record and return an ndarray"""
      self.time = fromfile(self.file, 'd', 1) [0]
      numItems = fromfile(self.file, 'i', 1) [0]
      if (numItems > 0):
         activity = fromfile(self.file, 'i', numItems)
      else:
         activity = []
      self.timestep += 1
      return activity
   # end next

   def read_params(self):
      """Read the file metadata parameters"""
      filepos = self.file.tell()
      self.numParams = fromfile(self.file, 'i', 2) [1]
      self.file.seek(filepos)
      self.params = fromfile(self.file, 'i', self.numParams)

      self.nx,self.ny,self.nf = self.params[3:6]
      self.nxProcs,self.nyProcs = self.params[5:7]
      #print 'nx = %d ny = %d nf = %d' % (self.nx,self.ny,self.nf)
   # end read_params

   def rewind(self):
      """Rewind the file to the start of the data (just past metadata)"""
      self.file.seek(4 * (self.numParams + 1))
   # end rewind

   def average_rate(self,timeSteps, rateSteps,dT):

      self.timeSteps = timeSteps
      self.rateSteps = rateSteps
      self.dT = dT    # 0.5; integration time step (miliseconds)
      self.rewind()
      average_rate = 0
      #print 'timeSteps = %d rateSteps = %d' % (self.timeSteps,self.rateSteps)

      # read transient time steps
      #print 'read transient time steps'
      while self.timestep < (self.timeSteps-self.rateSteps):
         #k = self.next_record()
         numItems = fromfile(self.file, 'i', 1)[0]
         if numItems > 0:
            #print 'timestep = %d numItems = %d: ' % (self.timestep,numItems),
            k = fromfile(self.file, 'i', numItems)
            #for i in range(len(k)):
            #   print '%d ' % k[i],
            #print '\n'
         else:
            average_rate += 0
            #print 'timestep = %d numItems = %d' % (self.timestep,numItems)
         self.timestep += 1

      self.timestep = 0
      # read time steps used to compute rate
      #print 'read time steps to compute rate'
      while self.timestep < self.rateSteps:
         #k = self.next_record()
         numItems = fromfile(self.file, 'i', 1)[0]
         if numItems > 0:
            #print 'timestep = %d numItems = %d: ' % (self.timestep,numItems),
            k = fromfile(self.file, 'i', numItems)
            #for i in range(len(k)):
            #   print '%d ' % k[i],
            #print '\n'
            average_rate += len(k)
         else:
            average_rate += 0
            #print 'timestep = %d numItems = %d' % (self.timestep,numItems)
         self.timestep += 1

      average_rate = (average_rate * 1000.0) / (self.timestep*self.nx*self.ny*self.nf*self.dT)
      return average_rate

   # end average_rate

# end class PVReadSparse

<|endoftext|>


<commit_before># Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, cint
from frappe import msgprint, _
from frappe.model.mapper import get_mapped_doc

from erpnext.utilities.transaction_base import TransactionBase

class Opportunity(TransactionBase):
	def get_item_details(self, item_code):
		item = frappe.db.sql("""select item_name, stock_uom, description_html, description, item_group, brand
			from `tabItem` where name = %s""", item_code, as_dict=1)
		ret = {
			'item_name': item and item[0]['item_name'] or '',
			'uom': item and item[0]['stock_uom'] or '',
			'description': item and item[0]['description_html'] or item[0]['description'] or '',
			'item_group': item and item[0]['item_group'] or '',
			'brand': item and item[0]['brand'] or ''
		}
		return ret

	def get_cust_address(self,name):
		details = frappe.db.sql("""select customer_name, address, territory, customer_group
			from `tabCustomer` where name = %s and docstatus != 2""", (name), as_dict = 1)
		if details:
			ret = {
				'customer_name':	details and details[0]['customer_name'] or '',
				'address'	:	details and details[0]['address'] or '',
				'territory'			 :	details and details[0]['territory'] or '',
				'customer_group'		:	details and details[0]['customer_group'] or ''
			}
			# ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)

			contact_det = frappe.db.sql("""select contact_name, contact_no, email_id
				from `tabContact` where customer = %s and is_customer = 1
					and is_primary_contact = 'Yes' and docstatus != 2""", name, as_dict = 1)

			ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
			ret['contact_no']		 = contact_det and contact_det[0]['contact_no'] or ''
			ret['email_id']			 = contact_det and contact_det[0]['email_id'] or ''

			return ret
		else:
			frappe.throw(_("Customer {0} does not exist").format(name), frappe.DoesNotExistError)

	def on_update(self):
		self.add_calendar_event()

	def add_calendar_event(self, opts=None, force=False):
		if not opts:
			opts = frappe._dict()

		opts.description = ""
		opts.contact_date = self.contact_date

		if self.customer:
			if self.contact_person:
				opts.description = 'Contact '+cstr(self.contact_person)
			else:
				opts.description = 'Contact customer '+cstr(self.customer)
		elif self.lead:
			if self.contact_display:
				opts.description = 'Contact '+cstr(self.contact_display)
			else:
				opts.description = 'Contact lead '+cstr(self.lead)

		opts.subject = opts.description
		opts.description += '. By : ' + cstr(self.contact_by)

		if self.to_discuss:
			opts.description += ' To Discuss : ' + cstr(self.to_discuss)

		super(Opportunity, self).add_calendar_event(opts, force)

	def validate_item_details(self):
		if not self.get('items'):
			frappe.throw(_("Items required"))

	def validate_lead_cust(self):
		if self.enquiry_from == 'Lead' and not self.lead:
			frappe.throw(_("Lead must be set if Opportunity is made from Lead"))
		elif self.enquiry_from == 'Customer' and not self.customer:
			msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)

	def validate(self):
		self._prev = frappe._dict({
			"contact_date": frappe.db.get_value("Opportunity", self.name, "contact_date") if \
				(not cint(self.get("__islocal"))) else None,
			"contact_by": frappe.db.get_value("Opportunity", self.name, "contact_by") if \
				(not cint(self.get("__islocal"))) else None,
		})

		self.set_status()
		self.validate_item_details()
		self.validate_uom_is_integer("uom", "qty")
		self.validate_lead_cust()

		from erpnext.accounts.utils import validate_fiscal_year
		validate_fiscal_year(self.transaction_date, self.fiscal_year, "Opportunity Date")

	def on_submit(self):
		if self.lead:
			frappe.get_doc("Lead", self.lead).set_status(update=True)

	def on_cancel(self):
		if self.has_quotation():
			frappe.throw(_("Cannot Cancel Opportunity as Quotation Exists"))
		self.set_status(update=True)

	def declare_enquiry_lost(self,arg):
		if not self.has_quotation():
			frappe.db.set(self, 'status', 'Lost')
			frappe.db.set(self, 'order_lost_reason', arg)
		else:
			frappe.throw(_("Cannot declare as lost, because Quotation has been made."))

	def on_trash(self):
		self.delete_events()

	def has_quotation(self):
		return frappe.db.get_value("Quotation Item", {"prevdoc_docname": self.name, "docstatus": 1})

@frappe.whitelist()
def make_quotation(source_name, target_doc=None):
	def set_missing_values(source, target):
		quotation = frappe.get_doc(target)
		quotation.run_method("set_missing_values")
		quotation.run_method("calculate_taxes_and_totals")

	doclist = get_mapped_doc("Opportunity", source_name, {
		"Opportunity": {
			"doctype": "Quotation",
			"field_map": {
				"enquiry_from": "quotation_to",
				"enquiry_type": "order_type",
				"name": "enq_no",
			},
			"validation": {
				"docstatus": ["=", 1]
			}
		},
		"Opportunity Item": {
			"doctype": "Quotation Item",
			"field_map": {
				"parent": "prevdoc_docname",
				"parenttype": "prevdoc_doctype",
				"uom": "stock_uom"
			},
			"add_if_empty": True
		}
	}, target_doc, set_missing_values)

	return doclist
<commit_msg>Opportunity From field is mandatory<commit_after># Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, cint
from frappe import msgprint, _
from frappe.model.mapper import get_mapped_doc

from erpnext.utilities.transaction_base import TransactionBase

class Opportunity(TransactionBase):
	def get_item_details(self, item_code):
		item = frappe.db.sql("""select item_name, stock_uom, description_html, description, item_group, brand
			from `tabItem` where name = %s""", item_code, as_dict=1)
		ret = {
			'item_name': item and item[0]['item_name'] or '',
			'uom': item and item[0]['stock_uom'] or '',
			'description': item and item[0]['description_html'] or item[0]['description'] or '',
			'item_group': item and item[0]['item_group'] or '',
			'brand': item and item[0]['brand'] or ''
		}
		return ret

	def get_cust_address(self,name):
		details = frappe.db.sql("""select customer_name, address, territory, customer_group
			from `tabCustomer` where name = %s and docstatus != 2""", (name), as_dict = 1)
		if details:
			ret = {
				'customer_name':	details and details[0]['customer_name'] or '',
				'address'	:	details and details[0]['address'] or '',
				'territory'			 :	details and details[0]['territory'] or '',
				'customer_group'		:	details and details[0]['customer_group'] or ''
			}
			# ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)

			contact_det = frappe.db.sql("""select contact_name, contact_no, email_id
				from `tabContact` where customer = %s and is_customer = 1
					and is_primary_contact = 'Yes' and docstatus != 2""", name, as_dict = 1)

			ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
			ret['contact_no']		 = contact_det and contact_det[0]['contact_no'] or ''
			ret['email_id']			 = contact_det and contact_det[0]['email_id'] or ''

			return ret
		else:
			frappe.throw(_("Customer {0} does not exist").format(name), frappe.DoesNotExistError)

	def on_update(self):
		self.add_calendar_event()

	def add_calendar_event(self, opts=None, force=False):
		if not opts:
			opts = frappe._dict()

		opts.description = ""
		opts.contact_date = self.contact_date

		if self.customer:
			if self.contact_person:
				opts.description = 'Contact '+cstr(self.contact_person)
			else:
				opts.description = 'Contact customer '+cstr(self.customer)
		elif self.lead:
			if self.contact_display:
				opts.description = 'Contact '+cstr(self.contact_display)
			else:
				opts.description = 'Contact lead '+cstr(self.lead)

		opts.subject = opts.description
		opts.description += '. By : ' + cstr(self.contact_by)

		if self.to_discuss:
			opts.description += ' To Discuss : ' + cstr(self.to_discuss)

		super(Opportunity, self).add_calendar_event(opts, force)

	def validate_item_details(self):
		if not self.get('items'):
			frappe.throw(_("Items required"))

	def validate_lead_cust(self):
		if self.enquiry_from == 'Lead' and not self.lead:
			frappe.throw(_("Lead must be set if Opportunity is made from Lead"))
		elif self.enquiry_from == 'Customer' and not self.customer:
			msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)

	def validate(self):
		self._prev = frappe._dict({
			"contact_date": frappe.db.get_value("Opportunity", self.name, "contact_date") if \
				(not cint(self.get("__islocal"))) else None,
			"contact_by": frappe.db.get_value("Opportunity", self.name, "contact_by") if \
				(not cint(self.get("__islocal"))) else None,
		})

		if not self.enquiry_from:
			frappe.throw(_("Opportunity From field is mandatory"))

		self.set_status()
		self.validate_item_details()
		self.validate_uom_is_integer("uom", "qty")
		self.validate_lead_cust()

		from erpnext.accounts.utils import validate_fiscal_year
		validate_fiscal_year(self.transaction_date, self.fiscal_year, "Opportunity Date")

	def on_submit(self):
		if self.lead:
			frappe.get_doc("Lead", self.lead).set_status(update=True)

	def on_cancel(self):
		if self.has_quotation():
			frappe.throw(_("Cannot Cancel Opportunity as Quotation Exists"))
		self.set_status(update=True)

	def declare_enquiry_lost(self,arg):
		if not self.has_quotation():
			frappe.db.set(self, 'status', 'Lost')
			frappe.db.set(self, 'order_lost_reason', arg)
		else:
			frappe.throw(_("Cannot declare as lost, because Quotation has been made."))

	def on_trash(self):
		self.delete_events()

	def has_quotation(self):
		return frappe.db.get_value("Quotation Item", {"prevdoc_docname": self.name, "docstatus": 1})

@frappe.whitelist()
def make_quotation(source_name, target_doc=None):
	def set_missing_values(source, target):
		quotation = frappe.get_doc(target)
		quotation.run_method("set_missing_values")
		quotation.run_method("calculate_taxes_and_totals")

	doclist = get_mapped_doc("Opportunity", source_name, {
		"Opportunity": {
			"doctype": "Quotation",
			"field_map": {
				"enquiry_from": "quotation_to",
				"enquiry_type": "order_type",
				"name": "enq_no",
			},
			"validation": {
				"docstatus": ["=", 1]
			}
		},
		"Opportunity Item": {
			"doctype": "Quotation Item",
			"field_map": {
				"parent": "prevdoc_docname",
				"parenttype": "prevdoc_doctype",
				"uom": "stock_uom"
			},
			"add_if_empty": True
		}
	}, target_doc, set_missing_values)

	return doclist
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Copyright (c) 2014, Vispy Development Team.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
"""
vispy backend for glfw.
"""

# Note: to install GLFW on Ubuntu:
# $ git clone git://github.com/glfw/glfw.git
# $ cd glfw
# $ cmake -DBUILD_SHARED_LIBS=true -DGLFW_BUILD_EXAMPLES=false \
#         -DGLFW_BUILD_TESTS=false -DGLFW_BUILD_DOCS=false .
# $ make
# $ sudo make install
# $ sudo apt-get -qq install libx11-dev

# On OSX, consider using brew.

from __future__ import division

import atexit

from ..base import BaseApplicationBackend, BaseCanvasBackend, BaseTimerBackend
from ...util import keys
from ...util.ptime import time

from . import _libglfw as glfw

if not glfw.glfwInit():  # only ever call once
    raise OSError('Could not init glfw')
atexit.register(glfw.glfwTerminate)

# Map native keys to vispy keys
KEYMAP = {
    glfw.GLFW_KEY_LEFT_SHIFT: keys.SHIFT,
    glfw.GLFW_KEY_RIGHT_SHIFT: keys.SHIFT,
    glfw.GLFW_KEY_LEFT_CONTROL: keys.CONTROL,
    glfw.GLFW_KEY_RIGHT_CONTROL: keys.CONTROL,
    glfw.GLFW_KEY_LEFT_ALT: keys.ALT,
    glfw.GLFW_KEY_RIGHT_ALT: keys.ALT,
    glfw.GLFW_KEY_LEFT_SUPER: keys.META,
    glfw.GLFW_KEY_RIGHT_SUPER: keys.META,

    glfw.GLFW_KEY_LEFT: keys.LEFT,
    glfw.GLFW_KEY_UP: keys.UP,
    glfw.GLFW_KEY_RIGHT: keys.RIGHT,
    glfw.GLFW_KEY_DOWN: keys.DOWN,
    glfw.GLFW_KEY_PAGE_UP: keys.PAGEUP,
    glfw.GLFW_KEY_PAGE_DOWN: keys.PAGEDOWN,

    glfw.GLFW_KEY_INSERT: keys.INSERT,
    glfw.GLFW_KEY_DELETE: keys.DELETE,
    glfw.GLFW_KEY_HOME: keys.HOME,
    glfw.GLFW_KEY_END: keys.END,

    glfw.GLFW_KEY_ESCAPE: keys.ESCAPE,
    glfw.GLFW_KEY_BACKSPACE: keys.BACKSPACE,

    glfw.GLFW_KEY_F1: keys.F1,
    glfw.GLFW_KEY_F2: keys.F2,
    glfw.GLFW_KEY_F3: keys.F3,
    glfw.GLFW_KEY_F4: keys.F4,
    glfw.GLFW_KEY_F5: keys.F5,
    glfw.GLFW_KEY_F6: keys.F6,
    glfw.GLFW_KEY_F7: keys.F7,
    glfw.GLFW_KEY_F8: keys.F8,
    glfw.GLFW_KEY_F9: keys.F9,
    glfw.GLFW_KEY_F10: keys.F10,
    glfw.GLFW_KEY_F11: keys.F11,
    glfw.GLFW_KEY_F12: keys.F12,

    glfw.GLFW_KEY_SPACE: keys.SPACE,
    glfw.GLFW_KEY_ENTER: keys.ENTER,
    '\r': keys.ENTER,
    glfw.GLFW_KEY_TAB: keys.TAB,
}

BUTTONMAP = {glfw.GLFW_MOUSE_BUTTON_LEFT: 1,
             glfw.GLFW_MOUSE_BUTTON_RIGHT: 2,
             glfw.GLFW_MOUSE_BUTTON_MIDDLE: 3
             }

_VP_GLFW_ALL_WINDOWS = []

MOD_KEYS = [keys.SHIFT, keys.ALT, keys.CONTROL, keys.META]

def _get_glfw_windows():
    wins = list()
    for win in _VP_GLFW_ALL_WINDOWS:
        if isinstance(win, CanvasBackend):
            wins.append(win)
    return wins

class ApplicationBackend(BaseApplicationBackend):

    def __init__(self):
        BaseApplicationBackend.__init__(self)
        self._timers = list()

    def _add_timer(self, timer):
        if timer not in self._timers:
            self._timers.append(timer)

    def _vispy_get_backend_name(self):
        return 'Glfw'

    def _vispy_process_events(self):
        glfw.glfwPollEvents()
        for timer in self._timers:
            timer._tick()
        wins = _get_glfw_windows()
        for win in wins:
            if win._needs_draw:
                win._needs_draw = False
                win._on_draw()

    def _vispy_run(self):
        wins = _get_glfw_windows()
        while all(w._id is not None and glfw.glfwWindowShouldClose(w._id)
                  for w in wins):
            self._vispy_process_events()
        self._vispy_quit()  # to clean up

    def _vispy_quit(self):
        # Close windows
        wins = _get_glfw_windows()
        for win in wins:
            win._vispy_close()
        # tear down timers
        for timer in self._timers:
            timer._vispy_stop()
        self._timers = []

    def _vispy_get_native_app(self):
        return glfw

class CanvasBackend(BaseCanvasBackend):

    """ Glfw backend for Canvas abstract class."""

    def __init__(self, name='glfw window', *args, **kwargs):
        BaseCanvasBackend.__init__(self)
        # Init GLFW, add window hints, and create window
        glfw.glfwWindowHint(glfw.GLFW_REFRESH_RATE, 0)
        glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, True)
        glfw.glfwWindowHint(glfw.GLFW_DEPTH_BITS, 24)
        glfw.glfwWindowHint(glfw.GLFW_RED_BITS, 8)
        glfw.glfwWindowHint(glfw.GLFW_GREEN_BITS, 8)
        glfw.glfwWindowHint(glfw.GLFW_BLUE_BITS, 8)
        glfw.glfwWindowHint(glfw.GLFW_ALPHA_BITS, 8)
        glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, True)
        glfw.glfwWindowHint(glfw.GLFW_DECORATED, True)
        glfw.glfwWindowHint(glfw.GLFW_VISIBLE, True)
        self._id = glfw.glfwCreateWindow(title=name)
        if not self._id:
            raise RuntimeError('Could not create window')
        _VP_GLFW_ALL_WINDOWS.append(self)
        glfw.glfwMakeContextCurrent(self._id)
        glfw.glfwHideWindow(self._id)  # Start hidden, like the other backends
        self._mod = list()

        # Register callbacks
        glfw.glfwSetWindowRefreshCallback(self._id, self._on_draw)
        glfw.glfwSetFramebufferSizeCallback(self._id, self._on_resize)
        glfw.glfwSetKeyCallback(self._id, self._on_key_press)
        glfw.glfwSetMouseButtonCallback(self._id, self._on_mouse_button)
        glfw.glfwSetScrollCallback(self._id, self._on_mouse_scroll)
        glfw.glfwSetCursorPosCallback(self._id, self._on_mouse_motion)
        glfw.glfwSetWindowCloseCallback(self._id, self._on_close)
        glfw.glfwSwapInterval(1)  # avoid tearing
        self._vispy_canvas_ = None
        self._needs_draw = False

    ###########################################################################
    # Deal with events we get from vispy
    @property
    def _vispy_canvas(self):
        """ The size of canvas/window """
        return self._vispy_canvas_

    @_vispy_canvas.setter
    def _vispy_canvas(self, vc):
        # Init events when the property is set by Canvas
        self._vispy_canvas_ = vc
        if vc is not None:
            self._vispy_canvas.events.initialize()
        return self._vispy_canvas

    def _vispy_set_current(self):
        if self._id is None:
            return
        # Make this the current context
        glfw.glfwMakeContextCurrent(self._id)

    def _vispy_swap_buffers(self):
        if self._id is None:
            return
        # Swap front and back buffer
        glfw.glfwSwapBuffers(self._id)

    def _vispy_set_title(self, title):
        if self._id is None:
            return
        # Set the window title. Has no effect for widgets
        glfw.glfwSetWindowTitle(self._id, title)

    def _vispy_set_size(self, w, h):
        if self._id is None:
            return
        # Set size of the widget or window
        glfw.glfwSetWindowSize(self._id, w, h)

    def _vispy_set_position(self, x, y):
        if self._id is None:
            return
        # Set position of the widget or window. May have no effect for widgets
        glfw.glfwSetWindowPos(self._id, x, y)

    def _vispy_set_visible(self, visible):
        # Show or hide the window or widget
        if self._id is None:
            return
        if visible:
            glfw.glfwShowWindow(self._id)
            # this ensures that the show takes effect
            self._vispy_update()
        else:
            glfw.glfwHideWindow(self._id)

    def _vispy_update(self):
        # Invoke a redraw, passing it on to the canvas
        if self._vispy_canvas is None or self._id is None:
            return
        # Mark that this window wants to be painted on the next loop iter
        self._needs_draw = True

    def _vispy_close(self):
        # Force the window or widget to shut down
        if self._id is not None:
            self._vispy_set_visible(False)
            id_ = self._id
            self._id = None
            glfw.glfwPollEvents()
            glfw.glfwDestroyWindow(id_)

    def _vispy_get_size(self):
        if self._id is None:
            return
        w, h = glfw.glfwGetFramebufferSize(self._id)
        return w, h

    def _vispy_get_position(self):
        if self._id is None:
            return
        x, y = glfw.glfwGetWindowPos(self._id)
        return x, y

    ###########################################################################
    # Notify vispy of events triggered by GLFW
    def _on_resize(self, _id, w, h):
        if self._vispy_canvas is None:
            return
        self._vispy_canvas.events.resize(size=(w, h))

    def _on_close(self, _id):
        if self._vispy_canvas is None:
            return
        self._vispy_canvas.events.close()

    def _on_draw(self, _id=None):
        if self._vispy_canvas is None or self._id is None:
            return
        self._vispy_set_current()
        self._vispy_canvas.events.paint(region=None)  # (0, 0, w, h))

    def _on_mouse_button(self, _id, button, action, mod):
        if self._vispy_canvas is None and self._id is not None:
            return
        pos = glfw.glfwGetCursorPos(self._id)
        if button < 3:
            # Mouse click event
            button = BUTTONMAP.get(button, 0)
            if action == glfw.GLFW_PRESS:
                fun = self._vispy_mouse_press
            elif action == glfw.GLFW_RELEASE:
                fun = self._vispy_mouse_release
            else:
                return
            fun(pos=pos, button=button, modifiers=self._mod)

    def _on_mouse_scroll(self, _id, x_off, y_off):
        if self._vispy_canvas is None and self._id is not None:
            return
        pos = glfw.glfwGetCursorPos(self._id)
        delta = (float(x_off), float(y_off))
        self._vispy_canvas.events.mouse_wheel(pos=pos, delta=delta,
                                              modifiers=self._mod)

    def _on_mouse_motion(self, _id, x, y):
        if self._vispy_canvas is None:
            return
        self._vispy_mouse_move(pos=(x, y), modifiers=self._mod)

    def _on_key_press(self, _id, key, scancode, action, mod):
        if self._vispy_canvas is None:
            return
        key, text = self._process_key(key)
        if action == glfw.GLFW_PRESS:
            fun = self._vispy_canvas.events.key_press
            down = True
        elif action == glfw.GLFW_RELEASE:
            fun = self._vispy_canvas.events.key_release
            down = False
        else:
            return
        self._process_mod(key, down=down)
        fun(key=key, text=text, modifiers=self._mod)

    def _process_key(self, key):
        if key in KEYMAP:
            return KEYMAP[key], ''
        elif 32 <= key <= 127:
            return keys.Key(chr(key)), chr(key)
        else:
            return None, ''

    def _process_mod(self, key, down):
        """Process (possible) keyboard modifiers

        GLFW provides "mod" with many callbacks, but not (critically) the
        scroll callback, so we keep track on our own here.
        """
        if key in MOD_KEYS:
            if down:
                if key not in self._mod:
                    self._mod.append(key)
            elif key in self._mod:
                self._mod.pop(self._mod.index(key))
        return self._mod

class TimerBackend(BaseTimerBackend):

    def __init__(self, vispy_timer):
        BaseTimerBackend.__init__(self, vispy_timer)
        vispy_timer._app._backend._add_timer(self)
        self._vispy_stop()

    def _vispy_start(self, interval):
        self._interval = interval
        self._next_time = time() + self._interval

    def _vispy_stop(self):
        self._next_time = float('inf')

    def _tick(self):
        if time() >= self._next_time:
            self._vispy_timer._timeout()
            self._next_time = time() + self._interval
<commit_msg>TEST: Test no glfw<commit_after># -*- coding: utf-8 -*-
# Copyright (c) 2014, Vispy Development Team.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
"""
vispy backend for glfw.
"""

# Note: to install GLFW on Ubuntu:
# $ git clone git://github.com/glfw/glfw.git
# $ cd glfw
# $ cmake -DBUILD_SHARED_LIBS=true -DGLFW_BUILD_EXAMPLES=false \
#         -DGLFW_BUILD_TESTS=false -DGLFW_BUILD_DOCS=false .
# $ make
# $ sudo make install
# $ sudo apt-get -qq install libx11-dev

# On OSX, consider using brew.

from __future__ import division

import atexit

from ..base import BaseApplicationBackend, BaseCanvasBackend, BaseTimerBackend
from ...util import keys
from ...util.ptime import time

from . import _libglfw as glfw

if not glfw.glfwInit():  # only ever call once
    raise OSError('Could not init glfw')
atexit.register(glfw.glfwTerminate)
raise ImportError  # XXX FOR TESTING ONLY

# Map native keys to vispy keys
KEYMAP = {
    glfw.GLFW_KEY_LEFT_SHIFT: keys.SHIFT,
    glfw.GLFW_KEY_RIGHT_SHIFT: keys.SHIFT,
    glfw.GLFW_KEY_LEFT_CONTROL: keys.CONTROL,
    glfw.GLFW_KEY_RIGHT_CONTROL: keys.CONTROL,
    glfw.GLFW_KEY_LEFT_ALT: keys.ALT,
    glfw.GLFW_KEY_RIGHT_ALT: keys.ALT,
    glfw.GLFW_KEY_LEFT_SUPER: keys.META,
    glfw.GLFW_KEY_RIGHT_SUPER: keys.META,

    glfw.GLFW_KEY_LEFT: keys.LEFT,
    glfw.GLFW_KEY_UP: keys.UP,
    glfw.GLFW_KEY_RIGHT: keys.RIGHT,
    glfw.GLFW_KEY_DOWN: keys.DOWN,
    glfw.GLFW_KEY_PAGE_UP: keys.PAGEUP,
    glfw.GLFW_KEY_PAGE_DOWN: keys.PAGEDOWN,

    glfw.GLFW_KEY_INSERT: keys.INSERT,
    glfw.GLFW_KEY_DELETE: keys.DELETE,
    glfw.GLFW_KEY_HOME: keys.HOME,
    glfw.GLFW_KEY_END: keys.END,

    glfw.GLFW_KEY_ESCAPE: keys.ESCAPE,
    glfw.GLFW_KEY_BACKSPACE: keys.BACKSPACE,

    glfw.GLFW_KEY_F1: keys.F1,
    glfw.GLFW_KEY_F2: keys.F2,
    glfw.GLFW_KEY_F3: keys.F3,
    glfw.GLFW_KEY_F4: keys.F4,
    glfw.GLFW_KEY_F5: keys.F5,
    glfw.GLFW_KEY_F6: keys.F6,
    glfw.GLFW_KEY_F7: keys.F7,
    glfw.GLFW_KEY_F8: keys.F8,
    glfw.GLFW_KEY_F9: keys.F9,
    glfw.GLFW_KEY_F10: keys.F10,
    glfw.GLFW_KEY_F11: keys.F11,
    glfw.GLFW_KEY_F12: keys.F12,

    glfw.GLFW_KEY_SPACE: keys.SPACE,
    glfw.GLFW_KEY_ENTER: keys.ENTER,
    '\r': keys.ENTER,
    glfw.GLFW_KEY_TAB: keys.TAB,
}

BUTTONMAP = {glfw.GLFW_MOUSE_BUTTON_LEFT: 1,
             glfw.GLFW_MOUSE_BUTTON_RIGHT: 2,
             glfw.GLFW_MOUSE_BUTTON_MIDDLE: 3
             }

_VP_GLFW_ALL_WINDOWS = []

MOD_KEYS = [keys.SHIFT, keys.ALT, keys.CONTROL, keys.META]

def _get_glfw_windows():
    wins = list()
    for win in _VP_GLFW_ALL_WINDOWS:
        if isinstance(win, CanvasBackend):
            wins.append(win)
    return wins

class ApplicationBackend(BaseApplicationBackend):

    def __init__(self):
        BaseApplicationBackend.__init__(self)
        self._timers = list()

    def _add_timer(self, timer):
        if timer not in self._timers:
            self._timers.append(timer)

    def _vispy_get_backend_name(self):
        return 'Glfw'

    def _vispy_process_events(self):
        glfw.glfwPollEvents()
        for timer in self._timers:
            timer._tick()
        wins = _get_glfw_windows()
        for win in wins:
            if win._needs_draw:
                win._needs_draw = False
                win._on_draw()

    def _vispy_run(self):
        wins = _get_glfw_windows()
        while all(w._id is not None and glfw.glfwWindowShouldClose(w._id)
                  for w in wins):
            self._vispy_process_events()
        self._vispy_quit()  # to clean up

    def _vispy_quit(self):
        # Close windows
        wins = _get_glfw_windows()
        for win in wins:
            win._vispy_close()
        # tear down timers
        for timer in self._timers:
            timer._vispy_stop()
        self._timers = []

    def _vispy_get_native_app(self):
        return glfw

class CanvasBackend(BaseCanvasBackend):

    """ Glfw backend for Canvas abstract class."""

    def __init__(self, name='glfw window', *args, **kwargs):
        BaseCanvasBackend.__init__(self)
        # Init GLFW, add window hints, and create window
        glfw.glfwWindowHint(glfw.GLFW_REFRESH_RATE, 0)
        glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, True)
        glfw.glfwWindowHint(glfw.GLFW_DEPTH_BITS, 24)
        glfw.glfwWindowHint(glfw.GLFW_RED_BITS, 8)
        glfw.glfwWindowHint(glfw.GLFW_GREEN_BITS, 8)
        glfw.glfwWindowHint(glfw.GLFW_BLUE_BITS, 8)
        glfw.glfwWindowHint(glfw.GLFW_ALPHA_BITS, 8)
        glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, True)
        glfw.glfwWindowHint(glfw.GLFW_DECORATED, True)
        glfw.glfwWindowHint(glfw.GLFW_VISIBLE, True)
        self._id = glfw.glfwCreateWindow(title=name)
        if not self._id:
            raise RuntimeError('Could not create window')
        _VP_GLFW_ALL_WINDOWS.append(self)
        glfw.glfwMakeContextCurrent(self._id)
        glfw.glfwHideWindow(self._id)  # Start hidden, like the other backends
        self._mod = list()

        # Register callbacks
        glfw.glfwSetWindowRefreshCallback(self._id, self._on_draw)
        glfw.glfwSetFramebufferSizeCallback(self._id, self._on_resize)
        glfw.glfwSetKeyCallback(self._id, self._on_key_press)
        glfw.glfwSetMouseButtonCallback(self._id, self._on_mouse_button)
        glfw.glfwSetScrollCallback(self._id, self._on_mouse_scroll)
        glfw.glfwSetCursorPosCallback(self._id, self._on_mouse_motion)
        glfw.glfwSetWindowCloseCallback(self._id, self._on_close)
        glfw.glfwSwapInterval(1)  # avoid tearing
        self._vispy_canvas_ = None
        self._needs_draw = False

    ###########################################################################
    # Deal with events we get from vispy
    @property
    def _vispy_canvas(self):
        """ The size of canvas/window """
        return self._vispy_canvas_

    @_vispy_canvas.setter
    def _vispy_canvas(self, vc):
        # Init events when the property is set by Canvas
        self._vispy_canvas_ = vc
        if vc is not None:
            self._vispy_canvas.events.initialize()
        return self._vispy_canvas

    def _vispy_set_current(self):
        if self._id is None:
            return
        # Make this the current context
        glfw.glfwMakeContextCurrent(self._id)

    def _vispy_swap_buffers(self):
        if self._id is None:
            return
        # Swap front and back buffer
        glfw.glfwSwapBuffers(self._id)

    def _vispy_set_title(self, title):
        if self._id is None:
            return
        # Set the window title. Has no effect for widgets
        glfw.glfwSetWindowTitle(self._id, title)

    def _vispy_set_size(self, w, h):
        if self._id is None:
            return
        # Set size of the widget or window
        glfw.glfwSetWindowSize(self._id, w, h)

    def _vispy_set_position(self, x, y):
        if self._id is None:
            return
        # Set position of the widget or window. May have no effect for widgets
        glfw.glfwSetWindowPos(self._id, x, y)

    def _vispy_set_visible(self, visible):
        # Show or hide the window or widget
        if self._id is None:
            return
        if visible:
            glfw.glfwShowWindow(self._id)
            # this ensures that the show takes effect
            self._vispy_update()
        else:
            glfw.glfwHideWindow(self._id)

    def _vispy_update(self):
        # Invoke a redraw, passing it on to the canvas
        if self._vispy_canvas is None or self._id is None:
            return
        # Mark that this window wants to be painted on the next loop iter
        self._needs_draw = True

    def _vispy_close(self):
        # Force the window or widget to shut down
        if self._id is not None:
            self._vispy_set_visible(False)
            id_ = self._id
            self._id = None
            glfw.glfwPollEvents()
            glfw.glfwDestroyWindow(id_)

    def _vispy_get_size(self):
        if self._id is None:
            return
        w, h = glfw.glfwGetFramebufferSize(self._id)
        return w, h

    def _vispy_get_position(self):
        if self._id is None:
            return
        x, y = glfw.glfwGetWindowPos(self._id)
        return x, y

    ###########################################################################
    # Notify vispy of events triggered by GLFW
    def _on_resize(self, _id, w, h):
        if self._vispy_canvas is None:
            return
        self._vispy_canvas.events.resize(size=(w, h))

    def _on_close(self, _id):
        if self._vispy_canvas is None:
            return
        self._vispy_canvas.events.close()

    def _on_draw(self, _id=None):
        if self._vispy_canvas is None or self._id is None:
            return
        self._vispy_set_current()
        self._vispy_canvas.events.paint(region=None)  # (0, 0, w, h))

    def _on_mouse_button(self, _id, button, action, mod):
        if self._vispy_canvas is None and self._id is not None:
            return
        pos = glfw.glfwGetCursorPos(self._id)
        if button < 3:
            # Mouse click event
            button = BUTTONMAP.get(button, 0)
            if action == glfw.GLFW_PRESS:
                fun = self._vispy_mouse_press
            elif action == glfw.GLFW_RELEASE:
                fun = self._vispy_mouse_release
            else:
                return
            fun(pos=pos, button=button, modifiers=self._mod)

    def _on_mouse_scroll(self, _id, x_off, y_off):
        if self._vispy_canvas is None and self._id is not None:
            return
        pos = glfw.glfwGetCursorPos(self._id)
        delta = (float(x_off), float(y_off))
        self._vispy_canvas.events.mouse_wheel(pos=pos, delta=delta,
                                              modifiers=self._mod)

    def _on_mouse_motion(self, _id, x, y):
        if self._vispy_canvas is None:
            return
        self._vispy_mouse_move(pos=(x, y), modifiers=self._mod)

    def _on_key_press(self, _id, key, scancode, action, mod):
        if self._vispy_canvas is None:
            return
        key, text = self._process_key(key)
        if action == glfw.GLFW_PRESS:
            fun = self._vispy_canvas.events.key_press
            down = True
        elif action == glfw.GLFW_RELEASE:
            fun = self._vispy_canvas.events.key_release
            down = False
        else:
            return
        self._process_mod(key, down=down)
        fun(key=key, text=text, modifiers=self._mod)

    def _process_key(self, key):
        if key in KEYMAP:
            return KEYMAP[key], ''
        elif 32 <= key <= 127:
            return keys.Key(chr(key)), chr(key)
        else:
            return None, ''

    def _process_mod(self, key, down):
        """Process (possible) keyboard modifiers

        GLFW provides "mod" with many callbacks, but not (critically) the
        scroll callback, so we keep track on our own here.
        """
        if key in MOD_KEYS:
            if down:
                if key not in self._mod:
                    self._mod.append(key)
            elif key in self._mod:
                self._mod.pop(self._mod.index(key))
        return self._mod

class TimerBackend(BaseTimerBackend):

    def __init__(self, vispy_timer):
        BaseTimerBackend.__init__(self, vispy_timer)
        vispy_timer._app._backend._add_timer(self)
        self._vispy_stop()

    def _vispy_start(self, interval):
        self._interval = interval
        self._next_time = time() + self._interval

    def _vispy_stop(self):
        self._next_time = float('inf')

    def _tick(self):
        if time() >= self._next_time:
            self._vispy_timer._timeout()
            self._next_time = time() + self._interval
<|endoftext|>