<commit_before>/*************************************************************************
 *
 *  $RCSfile: layerimport.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: rt $ $Date: 2003-12-01 12:04:46 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_FORMS_LAYERIMPORT_HXX_
#define _XMLOFF_FORMS_LAYERIMPORT_HXX_

#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HPP_
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif
#include <com/sun/star/container/XNameContainer.hpp>
#ifndef _VOS_REF_HXX_
#include <vos/ref.hxx>
#endif
#ifndef _XMLOFF_FORMATTRIBUTES_HXX_
#include "formattributes.hxx"
#endif
#ifndef _XMLOFF_FORMS_CALLBACKS_HXX_
#include "callbacks.hxx"
#endif
#ifndef _XMLOFF_FORMS_EVENTIMPORT_HXX_
#include "eventimport.hxx"
#endif
#ifndef _REF_HXX
#include <tools/ref.hxx>
#endif

class SvXMLImport;
class SvXMLImportContext;
class XMLPropertyHandlerFactory;
class SvXMLImportPropertyMapper;
class XMLPropStyleContext;

SV_DECL_REF( SvXMLStylesContext );
    // unfortunately, we can't put this into our namespace, as the macro expands to (amongst others) a forward
    // declaration of the class name, which then would be in the namespace, too

//.........................................................................
namespace xmloff
{
//.........................................................................

    class OAttribute2Property;

    //=====================================================================
    //= ControlReference
    //=====================================================================
    /// a structure containing a property set (the referred control) and a string (the list of referring controls)
/*  struct ControlReference
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                    xReferredControl;
        ::rtl::OUString
                    sReferringControls;

        ControlReference(
                const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxReferredControl,
                const ::rtl::OUString& _rReferringControls)
            :xReferredControl(_rxReferredControl)
            ,sReferringControls(_rReferringControls)
        {
        }
    };
*/

    //=====================================================================
    //= OFormLayerXMLImport_Impl
    //=====================================================================
    class OFormLayerXMLImport_Impl
                :public OAttributeMetaData
                ,public IControlIdMap
                ,public IFormsImportContext
                ,public ODefaultEventAttacherManager
    {
        friend class OFormLayerXMLImport;

    protected:
        SvXMLImport&                        m_rImporter;
        OAttribute2Property                 m_aAttributeMetaData;
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
                                            m_xForms;   // the forms of the currently imported page
        SvXMLStylesContext*                 m_pAutoStyles;

    protected:
        // style handling
        ::vos::ORef< XMLPropertyHandlerFactory >    m_xPropertyHandlerFactory;
        ::vos::ORef< SvXMLImportPropertyMapper >    m_xImportMapper;

        DECLARE_STL_USTRINGACCESS_MAP( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >, MapString2PropertySet );
        DECLARE_STL_MAP( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >, MapString2PropertySet, ODrawPageCompare, MapDrawPage2Map);

        MapDrawPage2Map         m_aControlIds;          // ids of the controls on all known page
        MapDrawPage2MapIterator m_aCurrentPageIds;      // ifs of the controls on the current page

        typedef ::std::pair< ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >, ::rtl::OUString >
                                ModelStringPair;
        ::std::vector< ModelStringPair >
                                m_aControlReferences;   // control reference descriptions for current page
        ::std::vector< ModelStringPair >
                                m_aCellValueBindings;   // information about controls bound to spreadsheet cells
        ::std::vector< ModelStringPair >
                                m_aCellRangeListSources;// information about controls bound to spreadsheet cell range list sources

    public:
        // IControlIdMap
        virtual void    registerControlId(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControl,
            const ::rtl::OUString& _rId);
        virtual void    registerControlReferences(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControl,
            const ::rtl::OUString& _rReferringControls);

        // IFormsImportContext
        virtual IControlIdMap&              getControlIdMap();
        virtual OAttribute2Property&        getAttributeMap();
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                                            getServiceFactory();
        virtual SvXMLImport&                getGlobalContext();
        const SvXMLStyleContext*            getStyleElement(const ::rtl::OUString& _rStyleName) const;
        virtual void                        enterEventContext();
        virtual void                        leaveEventContext();
        void                                applyControlNumberStyle(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rControlNumerStyleName
        );
        virtual void                        registerCellValueBinding(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rCellAddress
        );

        virtual void                        registerCellRangeListSource(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rCellRangeAddress
        );

    protected:
        OFormLayerXMLImport_Impl(SvXMLImport& _rImporter);
        ~OFormLayerXMLImport_Impl();

        /** retrieves the property mapper form form related auto styles.
        */
        ::vos::ORef< SvXMLImportPropertyMapper > getStylePropertyMapper() const;

        /** start importing the forms of the given page
        */
        void startPage(
            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& _rxDrawPage);

        /** end importing the forms of the current page
        */
        void endPage();

        /** creates an import context for the office:forms element
        */
        SvXMLImportContext* createOfficeFormsContext(
            SvXMLImport& _rImport,
            sal_uInt16 _nPrefix,
            const rtl::OUString& _rLocalName);

        /** create an <type>SvXMLImportContext</type> instance which is able to import the <form:form>
            element.
        */
        SvXMLImportContext* createContext(
            const sal_uInt16 _nPrefix,
            const rtl::OUString& _rLocalName,
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& _rxAttribs);

        /**
        */
        XMLPropStyleContext* createControlStyleContext(
            sal_uInt16 _nPrefix,
            const ::rtl::OUString& _rLocalName,
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& _rxAttrList,
            SvXMLStylesContext& _rParentStyles,
            sal_uInt16 _nFamily = 0,
            sal_Bool _bDefaultStyle = sal_False
        );

        /** get the control with the given id
        */
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                lookupControlId(const ::rtl::OUString& _rControlId);

        /** seek to the given page
        */
        void seekPage(
            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& _rxDrawPage);

        /** announces the auto-style context to the form importer
        */
        void setAutoStyleContext(SvXMLStylesContext* _pNewContext);

        /** to be called when the document has been completely imported

For some documents (currently: only some spreadsheet documents) it's necessary
            do to a post processing, since not all information from the file can be processed
            if the document is not completed, yet.

        */
        void documentDone( );
    };

//.........................................................................
}   // namespace xmloff
//.........................................................................

#endif // _XMLOFF_FORMS_LAYERIMPORT_HXX_

/*************************************************************************
 * history:
 *  $Log: not supported by cvs2svn $
 *  Revision 1.11.24.2  2003/11/24 15:19:46  obo
 *  undo last change
 *
 *  Revision 1.11  2003/10/21 08:40:18  obo
 *  INTEGRATION: CWS formcelllinkage (1.10.160); FILE MERGED
 *  2003/10/01 09:55:23 fs 1.10.160.1: #i18994# merging the changes from the CWS fs002
 *
 *  Revision 1.10.160.1  2003/10/01 09:55:23  fs
 *  #i18994# merging the changes from the CWS fs002
 *
 *  Revision 1.10.156.1  2003/09/25 14:28:41  fs
 *  #18994# merging the changes from cws_srx645_fs002 branch
 *
 *  Revision 1.10.152.1  2003/09/17 12:26:56  fs
 *  #18999# #19367# persistence for cell value and cell range bindings
 *
 *  Revision 1.10  2002/10/25 13:17:04  fs
 *  #104402# importing grid column styles now
 *
 *  Revision 1.9  2001/05/28 14:59:18  fs
 *  #86712# added control number style related functionality
 *
 *  Revision 1.8  2001/03/20 13:39:58  fs
 *  #83970# +createOfficeFormsContext
 *
 *  Revision 1.7  2001/02/01 09:46:47  fs
 *  no own style handling anymore - the shape exporter is responsible for our styles now
 *
 *  Revision 1.6  2001/01/24 09:34:40  fs
 *  +enter-/leaveEventContext
 *
 *  Revision 1.5  2001/01/02 15:58:22  fs
 *  event ex- & import
 *
 *  Revision 1.4  2000/12/18 15:14:35  fs
 *  some changes ... now exporting/importing styles
 *
 *  Revision 1.3  2000/12/13 10:40:15  fs
 *  new import related implementations - at this version, we should be able to import everything we export (which is all except events and styles)
 *
 *  Revision 1.2  2000/12/12 12:01:05  fs
 *  new implementations for the import - still under construction
 *
 *  Revision 1.1  2000/12/06 17:31:42  fs
 *  initial checkin - implementations for formlayer import/export - still under construction
 *
 *
 *  Revision 1.0 04.12.00 15:48:40  fs
 ************************************************************************/

<commit_msg>INTEGRATION: CWS oasis (1.12.66); FILE MERGED 2004/06/08 14:49:18 mib 1.12.66.1: - #i20153#: form controls<commit_after>/*************************************************************************
 *
 *  $RCSfile: layerimport.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: rt $ $Date: 2004-07-13 08:14:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_FORMS_LAYERIMPORT_HXX_
#define _XMLOFF_FORMS_LAYERIMPORT_HXX_

#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HPP_
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif
#include <com/sun/star/container/XNameContainer.hpp>
#ifndef _VOS_REF_HXX_
#include <vos/ref.hxx>
#endif
#ifndef _XMLOFF_FORMATTRIBUTES_HXX_
#include "formattributes.hxx"
#endif
#ifndef _XMLOFF_FORMS_CALLBACKS_HXX_
#include "callbacks.hxx"
#endif
#ifndef _XMLOFF_FORMS_EVENTIMPORT_HXX_
#include "eventimport.hxx"
#endif
#ifndef _REF_HXX
#include <tools/ref.hxx>
#endif

class SvXMLImport;
class SvXMLImportContext;
class XMLPropertyHandlerFactory;
class SvXMLImportPropertyMapper;
class XMLPropStyleContext;

SV_DECL_REF( SvXMLStylesContext );
    // unfortunately, we can't put this into our namespace, as the macro expands to (amongst others) a forward
    // declaration of the class name, which then would be in the namespace, too

//.........................................................................
namespace xmloff
{
//.........................................................................

    class OAttribute2Property;

    //=====================================================================
    //= ControlReference
    //=====================================================================
    /// a structure containing a property set (the referred control) and a string (the list of referring controls)
/*  struct ControlReference
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                    xReferredControl;
        ::rtl::OUString
                    sReferringControls;

        ControlReference(
                const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxReferredControl,
                const ::rtl::OUString& _rReferringControls)
            :xReferredControl(_rxReferredControl)
            ,sReferringControls(_rReferringControls)
        {
        }
    };
*/

    //=====================================================================
    //= OFormLayerXMLImport_Impl
    //=====================================================================
    class OFormLayerXMLImport_Impl
                :public OAttributeMetaData
                ,public IControlIdMap
                ,public IFormsImportContext
                ,public ODefaultEventAttacherManager
    {
        friend class OFormLayerXMLImport;

    protected:
        SvXMLImport&                        m_rImporter;
        OAttribute2Property                 m_aAttributeMetaData;
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
                                            m_xForms;   // the forms of the currently imported page
        SvXMLStylesContext*                 m_pAutoStyles;

    protected:
        // style handling
        ::vos::ORef< XMLPropertyHandlerFactory >    m_xPropertyHandlerFactory;
        ::vos::ORef< SvXMLImportPropertyMapper >    m_xImportMapper;

        DECLARE_STL_USTRINGACCESS_MAP( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >, MapString2PropertySet );
        DECLARE_STL_MAP( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >, MapString2PropertySet, ODrawPageCompare, MapDrawPage2Map);

        MapDrawPage2Map         m_aControlIds;          // ids of the controls on all known page
        MapDrawPage2MapIterator m_aCurrentPageIds;      // ifs of the controls on the current page

        typedef ::std::pair< ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >, ::rtl::OUString >
                                ModelStringPair;
        ::std::vector< ModelStringPair >
                                m_aControlReferences;   // control reference descriptions for current page
        ::std::vector< ModelStringPair >
                                m_aCellValueBindings;   // information about controls bound to spreadsheet cells
        ::std::vector< ModelStringPair >
                                m_aCellRangeListSources;// information about controls bound to spreadsheet cell range list sources

    public:
        // IControlIdMap
        virtual void    registerControlId(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControl,
            const ::rtl::OUString& _rId);
        virtual void    registerControlReferences(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControl,
            const ::rtl::OUString& _rReferringControls);

        // IFormsImportContext
        virtual IControlIdMap&              getControlIdMap();
        virtual OAttribute2Property&        getAttributeMap();
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                                            getServiceFactory();
        virtual SvXMLImport&                getGlobalContext();
        const SvXMLStyleContext*            getStyleElement(const ::rtl::OUString& _rStyleName) const;
        virtual void                        enterEventContext();
        virtual void                        leaveEventContext();
        void                                applyControlNumberStyle(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rControlNumerStyleName
        );
        virtual void                        registerCellValueBinding(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rCellAddress
        );

        virtual void                        registerCellRangeListSource(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rCellRangeAddress
        );

    protected:
        OFormLayerXMLImport_Impl(SvXMLImport& _rImporter);
        ~OFormLayerXMLImport_Impl();

        /** retrieves the property mapper form form related auto styles.
        */
        ::vos::ORef< SvXMLImportPropertyMapper > getStylePropertyMapper() const;

        /** start importing the forms of the given page
        */
        void startPage(
            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& _rxDrawPage);

        /** end importing the forms of the current page
        */
        void endPage();

        /** creates an import context for the office:forms element
        */
        SvXMLImportContext* createOfficeFormsContext(
            SvXMLImport& _rImport,
            sal_uInt16 _nPrefix,
            const rtl::OUString& _rLocalName);

        /** create an <type>SvXMLImportContext</type> instance which is able to import the <form:form>
            element.
        */
        SvXMLImportContext* createContext(
            const sal_uInt16 _nPrefix,
            const rtl::OUString& _rLocalName,
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& _rxAttribs);

        /** get the control with the given id
        */
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                lookupControlId(const ::rtl::OUString& _rControlId);

        /** seek to the given page
        */
        void seekPage(
            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& _rxDrawPage);

        /** announces the auto-style context to the form importer
        */
        void setAutoStyleContext(SvXMLStylesContext* _pNewContext);

        /** to be called when the document has been completely imported

For some documents (currently: only some spreadsheet documents) it's necessary
            do to a post processing, since not all information from the file can be processed
            if the document is not completed, yet.

        */
        void documentDone( );
    };

//.........................................................................
}   // namespace xmloff
//.........................................................................

#endif // _XMLOFF_FORMS_LAYERIMPORT_HXX_

/*************************************************************************
 * history:
 *  $Log: not supported by cvs2svn $
 *  Revision 1.12.66.1  2004/06/08 14:49:18  mib
 *  - #i20153#: form controls
 *
 *  Revision 1.12  2003/12/01 12:04:46  rt
 *  INTEGRATION: CWS geordi2q09 (1.11.24); FILE MERGED
 *  2003/11/24 15:19:46 obo 1.11.24.2: undo last change
 *  2003/11/21 17:04:39 obo 1.11.24.1: #111934# join CWS comboboxlink
 *
 *  Revision 1.11.24.2  2003/11/24 15:19:46  obo
 *  undo last change
 *
 *  Revision 1.11  2003/10/21 08:40:18  obo
 *  INTEGRATION: CWS formcelllinkage (1.10.160); FILE MERGED
 *  2003/10/01 09:55:23 fs 1.10.160.1: #i18994# merging the changes from the CWS fs002
 *
 *  Revision 1.10.160.1  2003/10/01 09:55:23  fs
 *  #i18994# merging the changes from the CWS fs002
 *
 *  Revision 1.10.156.1  2003/09/25 14:28:41  fs
 *  #18994# merging the changes from cws_srx645_fs002 branch
 *
 *  Revision 1.10.152.1  2003/09/17 12:26:56  fs
 *  #18999# #19367# persistence for cell value and cell range bindings
 *
 *  Revision 1.10  2002/10/25 13:17:04  fs
 *  #104402# importing grid column styles now
 *
 *  Revision 1.9  2001/05/28 14:59:18  fs
 *  #86712# added control number style related functionality
 *
 *  Revision 1.8  2001/03/20 13:39:58  fs
 *  #83970# +createOfficeFormsContext
 *
 *  Revision 1.7  2001/02/01 09:46:47  fs
 *  no own style handling anymore - the shape exporter is responsible for our styles now
 *
 *  Revision 1.6  2001/01/24 09:34:40  fs
 *  +enter-/leaveEventContext
 *
 *  Revision 1.5  2001/01/02 15:58:22  fs
 *  event ex- & import
 *
 *  Revision 1.4  2000/12/18 15:14:35  fs
 *  some changes ... now exporting/importing styles
 *
 *  Revision 1.3  2000/12/13 10:40:15  fs
 *  new import related implementations - at this version, we should be able to import everything we export (which is all except events and styles)
 *
 *  Revision 1.2  2000/12/12 12:01:05  fs
 *  new implementations for the import - still under construction
 *
 *  Revision 1.1  2000/12/06 17:31:42  fs
 *  initial checkin - implementations for formlayer import/export - still under construction
 *
 *
 *  Revision 1.0 04.12.00 15:48:40  fs
 ************************************************************************/

<|endoftext|>


<commit_before>/*
 * @file: adaboost_main.cpp
 * @author: Udit Saxena
 *
 * Implementation of the AdaBoost main file
 *
 *  @code
 *  @article{Schapire:1999:IBA:337859.337870,
 *  author = {Schapire, Robert E. and Singer, Yoram},
 *  title = {Improved Boosting Algorithms Using Confidence-rated Predictions},
 *  journal = {Mach. Learn.},
 *  issue_date = {Dec. 1999},
 *  volume = {37},
 *  number = {3},
 *  month = dec,
 *  year = {1999},
 *  issn = {0885-6125},
 *  pages = {297--336},
 *  numpages = {40},
 *  url = {http://dx.doi.org/10.1023/A:1007614523901},
 *  doi = {10.1023/A:1007614523901},
 *  acmid = {337870},
 *  publisher = {Kluwer Academic Publishers},
 *  address = {Hingham, MA, USA},
 *  keywords = {boosting algorithms, decision trees, multiclass classification,
 *  output coding
 *  }
 *  @endcode
 *
 */

#include <mlpack/core.hpp>
#include "adaboost.hpp"

using namespace mlpack;
using namespace std;
using namespace arma;
using namespace mlpack::adaboost;

PROGRAM_INFO("AdaBoost","This program implements the AdaBoost (or Adaptive Boost)"
 " algorithm. The variant of AdaBoost implemented here is AdaBoost.mh. It uses a"
 " weak learner, either of Decision Stumps or a Perceptron, and over many"
 " iterations, creates a strong learner. It runs these iterations till a tolerance"
 " value is crossed for change in the value of rt."
 "\n"
 "This program allows training of a adaboost object, and then application of "
 "the strong learner to a test dataset.  To train "
 "a training dataset must be passed to --train_file (-t).  Labels can either"
 " be present as the last dimension of the training dataset, or given "
 "explicitly with the --labels_file (-l) parameter.\n"
 "\n"
 "A test file is given through the --test_file (-T) parameter.  The "
 "predicted labels for the test set will be stored in the file specified by "
 "the --output_file (-o) parameter.");

//necessary parameters
PARAM_STRING_REQ("train_file", "A file containing the training set.", "t");
PARAM_STRING_REQ("labels_file", "A file containing labels for the training set.",
  "l");
PARAM_STRING_REQ("test_file", "A file containing the test set.", "T");

//optional parameters.
PARAM_STRING("output", "The file in which the predicted labels for the test set"
    " will be written.", "o", "output.csv");
PARAM_INT("iterations","The maximum number of boosting iterations "
  "to be run", "i", 1000);
PARAM_DOUBLE("tolerance","The tolerance for change in values of rt","e",1e-10);

int main(int argc, char *argv[])
{
  CLI::ParseCommandLine(argc, argv);

  const string trainingDataFilename = CLI::GetParam<string>("train_file");
  mat trainingData;
  data::Load(trainingDataFilename, trainingData, true);

  const string labelsFilename = CLI::GetParam<string>("labels_file");
  // Load labels.
  mat labelsIn;
  // data::Load(labelsFilename, labelsIn, true);

  if (CLI::HasParam("labels_file"))
  {
    const string labelsFilename = CLI::GetParam<string>("labels_file");
    // Load labels.
    data::Load(labelsFilename, labelsIn, true);

    // Do the labels need to be transposed?
    if (labelsIn.n_rows == 1)
      labelsIn = labelsIn.t();
  }
  else
  {
    // Extract the labels as the last
    Log::Info << "Using the last dimension of training set as labels." << endl;

    labelsIn = trainingData.row(trainingData.n_rows - 1).t();
    trainingData.shed_row(trainingData.n_rows - 1);
  }

  // helpers for normalizing the labels
  Col<size_t> labels;
  vec mappings;

  // Do the labels need to be transposed?
  if (labelsIn.n_rows == 1)
    labelsIn = labelsIn.t();

  // normalize the labels
  data::NormalizeLabels(labelsIn.unsafe_col(0), labels, mappings);

  const string testingDataFilename = CLI::GetParam<string>("test_file");
  mat testingData;
  data::Load(testingDataFilename, testingData, true);

  const double tolerance = CLI::GetParam<double>("tolerance");

  if (testingData.n_rows != trainingData.n_rows)
    Log::Fatal << "Test data dimensionality (" << testingData.n_rows << ") "
        << "must be the same as training data (" << trainingData.n_rows - 1
        << ")!" << std::endl;
  int iterations = CLI::GetParam<int>("iterations");

  // define your own weak learner, perceptron in this case.
  // defining the number of iterations of the perceptron.
  int iter = 400;

  perceptron::Perceptron<> p(trainingData, labels.t(), iter);

  Timer::Start("Training");
  AdaBoost<> a(trainingData, labels.t(), iterations, tolerance, p);
  Timer::Stop("Training");

  Row<size_t> predictedLabels(testingData.n_cols);
  Timer::Start("testing");
  a.Classify(testingData, predictedLabels);
  Timer::Stop("testing");

  vec results;
  data::RevertLabels(predictedLabels.t(), mappings, results);

  // Save the predicted labels in a transposed form as output.
  const string outputFilename = CLI::GetParam<string>("output_file");
  data::Save(outputFilename, results, true, false);
  return 0;
}<commit_msg>Fix Adaboost executable for Perceptron API change.<commit_after>/*
 * @file: adaboost_main.cpp
 * @author: Udit Saxena
 *
 * Implementation of the AdaBoost main file
 *
 *  @code
 *  @article{Schapire:1999:IBA:337859.337870,
 *  author = {Schapire, Robert E. and Singer, Yoram},
 *  title = {Improved Boosting Algorithms Using Confidence-rated Predictions},
 *  journal = {Mach. Learn.},
 *  issue_date = {Dec. 1999},
 *  volume = {37},
 *  number = {3},
 *  month = dec,
 *  year = {1999},
 *  issn = {0885-6125},
 *  pages = {297--336},
 *  numpages = {40},
 *  url = {http://dx.doi.org/10.1023/A:1007614523901},
 *  doi = {10.1023/A:1007614523901},
 *  acmid = {337870},
 *  publisher = {Kluwer Academic Publishers},
 *  address = {Hingham, MA, USA},
 *  keywords = {boosting algorithms, decision trees, multiclass classification,
 *  output coding
 *  }
 *  @endcode
 *
 */

#include <mlpack/core.hpp>
#include "adaboost.hpp"

using namespace mlpack;
using namespace std;
using namespace arma;
using namespace mlpack::adaboost;

PROGRAM_INFO("AdaBoost","This program implements the AdaBoost (or Adaptive Boost)"
 " algorithm. The variant of AdaBoost implemented here is AdaBoost.mh. It uses a"
 " weak learner, either of Decision Stumps or a Perceptron, and over many"
 " iterations, creates a strong learner. It runs these iterations till a tolerance"
 " value is crossed for change in the value of rt."
 "\n"
 "This program allows training of a adaboost object, and then application of "
 "the strong learner to a test dataset.  To train "
 "a training dataset must be passed to --train_file (-t).  Labels can either"
 " be present as the last dimension of the training dataset, or given "
 "explicitly with the --labels_file (-l) parameter.\n"
 "\n"
 "A test file is given through the --test_file (-T) parameter.  The "
 "predicted labels for the test set will be stored in the file specified by "
 "the --output_file (-o) parameter.");

//necessary parameters
PARAM_STRING_REQ("train_file", "A file containing the training set.", "t");
PARAM_STRING_REQ("labels_file", "A file containing labels for the training set.",
  "l");
PARAM_STRING_REQ("test_file", "A file containing the test set.", "T");

//optional parameters.
PARAM_STRING("output", "The file in which the predicted labels for the test set"
    " will be written.", "o", "output.csv");
PARAM_INT("iterations","The maximum number of boosting iterations "
  "to be run", "i", 1000);
PARAM_DOUBLE("tolerance","The tolerance for change in values of rt","e",1e-10);

int main(int argc, char *argv[])
{
  CLI::ParseCommandLine(argc, argv);

  const string trainingDataFilename = CLI::GetParam<string>("train_file");
  mat trainingData;
  data::Load(trainingDataFilename, trainingData, true);

  const string labelsFilename = CLI::GetParam<string>("labels_file");
  // Load labels.
  mat labelsIn;
  // data::Load(labelsFilename, labelsIn, true);

  if (CLI::HasParam("labels_file"))
  {
    const string labelsFilename = CLI::GetParam<string>("labels_file");
    // Load labels.
    data::Load(labelsFilename, labelsIn, true);

    // Do the labels need to be transposed?
    if (labelsIn.n_rows == 1)
      labelsIn = labelsIn.t();
  }
  else
  {
    // Extract the labels as the last
    Log::Info << "Using the last dimension of training set as labels." << endl;

    labelsIn = trainingData.row(trainingData.n_rows - 1).t();
    trainingData.shed_row(trainingData.n_rows - 1);
  }

  // helpers for normalizing the labels
  Col<size_t> labels;
  vec mappings;

  // Do the labels need to be transposed?
  if (labelsIn.n_rows == 1)
    labelsIn = labelsIn.t();

  // normalize the labels
  data::NormalizeLabels(labelsIn.unsafe_col(0), labels, mappings);

  const string testingDataFilename = CLI::GetParam<string>("test_file");
  mat testingData;
  data::Load(testingDataFilename, testingData, true);

  const double tolerance = CLI::GetParam<double>("tolerance");

  if (testingData.n_rows != trainingData.n_rows)
    Log::Fatal << "Test data dimensionality (" << testingData.n_rows << ") "
        << "must be the same as training data (" << trainingData.n_rows - 1
        << ")!" << std::endl;
  int iterations = CLI::GetParam<int>("iterations");

  // define your own weak learner, perceptron in this case.
  // defining the number of iterations of the perceptron.
  int iter = 400;

  perceptron::Perceptron<> p(trainingData, labels.t(), max(labels) + 1, iter);

  Timer::Start("Training");
  AdaBoost<> a(trainingData, labels.t(), iterations, tolerance, p);
  Timer::Stop("Training");

  Row<size_t> predictedLabels(testingData.n_cols);
  Timer::Start("testing");
  a.Classify(testingData, predictedLabels);
  Timer::Stop("testing");

  vec results;
  data::RevertLabels(predictedLabels.t(), mappings, results);

  // Save the predicted labels in a transposed form as output.
  const string outputFilename = CLI::GetParam<string>("output_file");
  data::Save(outputFilename, results, true, false);
  return 0;
}
<|endoftext|>


<commit_before>/**
 * @file dtnn_rules_impl.hpp
 * @author Ryan Curtin
 *
 * Implementation of DualTreeKMeansRules.
 */
#ifndef __MLPACK_METHODS_KMEANS_DTNN_RULES_IMPL_HPP
#define __MLPACK_METHODS_KMEANS_DTNN_RULES_IMPL_HPP

#include "dtnn_rules.hpp"

namespace mlpack {
namespace kmeans {

template<typename MetricType, typename TreeType>
DTNNKMeansRules<MetricType, TreeType>::DTNNKMeansRules(
    const arma::mat& centroids,
    const arma::mat& dataset,
    arma::Col<size_t>& assignments,
    arma::vec& upperBounds,
    arma::vec& lowerBounds,
    MetricType& metric,
    const std::vector<bool>& prunedPoints,
    const std::vector<size_t>& oldFromNewCentroids,
    std::vector<bool>& visited) :
    centroids(centroids),
    dataset(dataset),
    assignments(assignments),
    upperBounds(upperBounds),
    lowerBounds(lowerBounds),
    metric(metric),
    prunedPoints(prunedPoints),
    oldFromNewCentroids(oldFromNewCentroids),
    visited(visited),
    baseCases(0),
    scores(0),
    lastQueryIndex(dataset.n_cols),
    lastReferenceIndex(centroids.n_cols)
{
  // We must set the traversal info last query and reference node pointers to
  // something that is both invalid (i.e. not a tree node) and not NULL.  We'll
  // use the this pointer.
  traversalInfo.LastQueryNode() = (TreeType*) this;
  traversalInfo.LastReferenceNode() = (TreeType*) this;
}

template<typename MetricType, typename TreeType>
inline force_inline double DTNNKMeansRules<MetricType, TreeType>::BaseCase(
    const size_t queryIndex,
    const size_t referenceIndex)
{
  if (prunedPoints[queryIndex])
    return 0.0; // Returning 0 shouldn't be a problem.

  // If we have already performed this base case, then do not perform it again.
  if ((lastQueryIndex == queryIndex) && (lastReferenceIndex == referenceIndex))
    return lastBaseCase;

  // Any base cases imply that we will get a result.
  visited[queryIndex] = true;

  // Calculate the distance.
  ++baseCases;
  const double distance = metric.Evaluate(dataset.col(queryIndex),
                                          centroids.col(referenceIndex));

  if (distance < upperBounds[queryIndex])
  {
    lowerBounds[queryIndex] = upperBounds[queryIndex];
    upperBounds[queryIndex] = distance;
    assignments[queryIndex] = (tree::TreeTraits<TreeType>::RearrangesDataset) ?
        oldFromNewCentroids[referenceIndex] : referenceIndex;
  }
  else if (distance < lowerBounds[queryIndex])
  {
    lowerBounds[queryIndex] = distance;
  }

  // Cache this information for the next time BaseCase() is called.
  lastQueryIndex = queryIndex;
  lastReferenceIndex = referenceIndex;
  lastBaseCase = distance;

  return distance;
}

template<typename MetricType, typename TreeType>
inline double DTNNKMeansRules<MetricType, TreeType>::Score(
    const size_t queryIndex,
    TreeType& /* referenceNode */)
{
  // If the query point has already been pruned, then don't recurse further.
  if (prunedPoints[queryIndex])
    return DBL_MAX;

  // No pruning at this level; we're not likely to encounter a single query
  // point with a reference node..
  return 0;
}

template<typename MetricType, typename TreeType>
inline double DTNNKMeansRules<MetricType, TreeType>::Score(
    TreeType& queryNode,
    TreeType& referenceNode)
{
  if (queryNode.Stat().StaticPruned() == true)
    return DBL_MAX;

  // Pruned() for the root node must never be set to size_t(-1).
  if (queryNode.Stat().Pruned() == size_t(-1))
  {
    queryNode.Stat().Pruned() = queryNode.Parent()->Stat().Pruned();
    queryNode.Stat().LowerBound() = queryNode.Parent()->Stat().LowerBound();
    queryNode.Stat().Owner() = queryNode.Parent()->Stat().Owner();
  }

  if (queryNode.Stat().Pruned() == centroids.n_cols)
    return DBL_MAX;

  // This looks a lot like the hackery used in NeighborSearchRules to avoid
  // distance computations.  We'll use the traversal info to see if a
  // parent-child or parent-parent prune is possible.
  const double queryParentDist = queryNode.ParentDistance();
  const double queryDescDist = queryNode.FurthestDescendantDistance();
  const double refParentDist = referenceNode.ParentDistance();
  const double refDescDist = referenceNode.FurthestDescendantDistance();
  const double lastScore = traversalInfo.LastScore();
  double adjustedScore;
  double score = 0.0;

  // We want to set adjustedScore to be the distance between the centroid of the
  // last query node and last reference node.  We will do this by adjusting the
  // last score.  In some cases, we can just use the last base case.
  if (tree::TreeTraits<TreeType>::FirstPointIsCentroid)
  {
    adjustedScore = traversalInfo.LastBaseCase();
  }
  else if (lastScore == 0.0) // Nothing we can do here.
  {
    adjustedScore = 0.0;
  }
  else
  {
    // The last score is equal to the distance between the centroids minus the
    // radii of the query and reference bounds along the axis of the line
    // between the two centroids.  In the best case, these radii are the
    // furthest descendant distances, but that is not always true.  It would
    // take too long to calculate the exact radii, so we are forced to use
    // MinimumBoundDistance() as a lower-bound approximation.
    const double lastQueryDescDist =
        traversalInfo.LastQueryNode()->MinimumBoundDistance();
    const double lastRefDescDist =
        traversalInfo.LastReferenceNode()->MinimumBoundDistance();
    adjustedScore = lastScore + lastQueryDescDist;
    adjustedScore = lastScore + lastRefDescDist;
  }

  // Assemble an adjusted score.  For nearest neighbor search, this adjusted
  // score is a lower bound on MinDistance(queryNode, referenceNode) that is
  // assembled without actually calculating MinDistance().  For furthest
  // neighbor search, it is an upper bound on
  // MaxDistance(queryNode, referenceNode).  If the traversalInfo isn't usable
  // then the node should not be pruned by this.
  if (traversalInfo.LastQueryNode() == queryNode.Parent())
  {
    const double queryAdjust = queryParentDist + queryDescDist;
    adjustedScore -= queryAdjust;
  }
  else if (traversalInfo.LastQueryNode() == &queryNode)
  {
    adjustedScore -= queryDescDist;
  }
  else
  {
    // The last query node wasn't this query node or its parent.  So we force
    // the adjustedScore to be such that this combination can't be pruned here,
    // because we don't really know anything about it.

    // It would be possible to modify this section to try and make a prune based
    // on the query descendant distance and the distance between the query node
    // and last traversal query node, but this case doesn't actually happen for
    // kd-trees or cover trees.
    adjustedScore = 0.0;
  }
  if (traversalInfo.LastReferenceNode() == referenceNode.Parent())
  {
    const double refAdjust = refParentDist + refDescDist;
    adjustedScore -= refAdjust;
  }
  else if (traversalInfo.LastReferenceNode() == &referenceNode)
  {
    adjustedScore -= refDescDist;
  }
  else
  {
    // The last reference node wasn't this reference node or its parent.  So we
    // force the adjustedScore to be such that this combination can't be pruned
    // here, because we don't really know anything about it.

    // It would be possible to modify this section to try and make a prune based
    // on the reference descendant distance and the distance between the
    // reference node and last traversal reference node, but this case doesn't
    // actually happen for kd-trees or cover trees.
    adjustedScore = 0.0;
  }

  // Now, check if we can prune.
  //Log::Warn << "adjusted score: " << adjustedScore << ".\n";
  if (adjustedScore > queryNode.Stat().UpperBound())
  {
//    Log::Warn << "Pre-emptive prune!\n";
    if (!(tree::TreeTraits<TreeType>::FirstPointIsCentroid && score == 0.0))
    {
      // There isn't any need to set the traversal information because no
      // descendant combinations will be visited, and those are the only
      // combinations that would depend on the traversal information.
      if (adjustedScore < queryNode.Stat().LowerBound())
      {
        // If this might affect the lower bound, make it more exact.
        queryNode.Stat().LowerBound() = std::min(queryNode.Stat().LowerBound(),
            queryNode.MinDistance(&referenceNode));
        ++scores;
      }

      queryNode.Stat().Pruned() += referenceNode.NumDescendants();
      score = DBL_MAX;
    }
  }

  if (score != DBL_MAX)
  {
    // Get minimum and maximum distances.
    const math::Range distances = queryNode.RangeDistance(&referenceNode);

    score = distances.Lo();
    ++scores;
    if (distances.Lo() > queryNode.Stat().UpperBound())
    {
      // The reference node can own no points in this query node.  We may
      // improve the lower bound on pruned nodes, though.
      if (distances.Lo() < queryNode.Stat().LowerBound())
        queryNode.Stat().LowerBound() = distances.Lo();

      // This assumes that reference clusters don't appear elsewhere in the
      // tree.
      queryNode.Stat().Pruned() += referenceNode.NumDescendants();
      score = DBL_MAX;
    }
    else if (distances.Hi() < queryNode.Stat().UpperBound())
    {
      // Tighten upper bound.
      const double tighterBound =
          queryNode.MaxDistance(centroids.col(referenceNode.Descendant(0)));
      ++scores; // Count extra distance calculation.

      if (tighterBound <= queryNode.Stat().UpperBound())
      {
        // We can improve the best estimate.
        queryNode.Stat().UpperBound() = tighterBound;
        // If this node has only one descendant, then it may be the owner.
        if (referenceNode.NumDescendants() == 1)
          queryNode.Stat().Owner() =
              (tree::TreeTraits<TreeType>::RearrangesDataset) ?
              oldFromNewCentroids[referenceNode.Descendant(0)] :
              referenceNode.Descendant(0);
      }
    }
  }

  // Is everything pruned?
  if (queryNode.Stat().Pruned() == centroids.n_cols - 1)
  {
    queryNode.Stat().Pruned() = centroids.n_cols; // Owner() is already set.
    return DBL_MAX;
  }

  // Set traversal information.
  traversalInfo.LastQueryNode() = &queryNode;
  traversalInfo.LastReferenceNode() = &referenceNode;
  traversalInfo.LastScore() = score;

  return score;
}

template<typename MetricType, typename TreeType>
inline double DTNNKMeansRules<MetricType, TreeType>::Rescore(
    const size_t /* queryIndex */,
    TreeType& /* referenceNode */,
    const double oldScore)
{
  // No rescoring (for now).
  return oldScore;
}

template<typename MetricType, typename TreeType>
inline double DTNNKMeansRules<MetricType, TreeType>::Rescore(
    TreeType& queryNode,
    TreeType& referenceNode,
    const double oldScore)
{
  if (oldScore == DBL_MAX)
    return DBL_MAX; // It's already pruned.

  // oldScore contains the minimum distance between queryNode and referenceNode.
  // In the time since Score() has been called, the upper bound *may* have
  // tightened.  If it has tightened enough, we may prune this node now.
  if (oldScore > queryNode.Stat().UpperBound())
  {
    // We may still be able to improve the lower bound on pruned nodes.
    if (oldScore < queryNode.Stat().LowerBound())
      queryNode.Stat().LowerBound() = oldScore;

    // This assumes that reference clusters don't appear elsewhere in the tree.
    queryNode.Stat().Pruned() += referenceNode.NumDescendants();
    return DBL_MAX;
  }

  // Also, check if everything has been pruned.
  if (queryNode.Stat().Pruned() == centroids.n_cols - 1)
  {
    queryNode.Stat().Pruned() = centroids.n_cols; // Owner() is already set.
    return DBL_MAX;
  }

  return oldScore;
}

} // namespace kmeans
} // namespace mlpack

#endif
<commit_msg>Always mark the owner. This fixes some unusual and unexpected floating point errors where the owner will not actually be set.<commit_after>/**
 * @file dtnn_rules_impl.hpp
 * @author Ryan Curtin
 *
 * Implementation of DualTreeKMeansRules.
 */
#ifndef __MLPACK_METHODS_KMEANS_DTNN_RULES_IMPL_HPP
#define __MLPACK_METHODS_KMEANS_DTNN_RULES_IMPL_HPP

#include "dtnn_rules.hpp"

namespace mlpack {
namespace kmeans {

template<typename MetricType, typename TreeType>
DTNNKMeansRules<MetricType, TreeType>::DTNNKMeansRules(
    const arma::mat& centroids,
    const arma::mat& dataset,
    arma::Col<size_t>& assignments,
    arma::vec& upperBounds,
    arma::vec& lowerBounds,
    MetricType& metric,
    const std::vector<bool>& prunedPoints,
    const std::vector<size_t>& oldFromNewCentroids,
    std::vector<bool>& visited) :
    centroids(centroids),
    dataset(dataset),
    assignments(assignments),
    upperBounds(upperBounds),
    lowerBounds(lowerBounds),
    metric(metric),
    prunedPoints(prunedPoints),
    oldFromNewCentroids(oldFromNewCentroids),
    visited(visited),
    baseCases(0),
    scores(0),
    lastQueryIndex(dataset.n_cols),
    lastReferenceIndex(centroids.n_cols)
{
  // We must set the traversal info last query and reference node pointers to
  // something that is both invalid (i.e. not a tree node) and not NULL.  We'll
  // use the this pointer.
  traversalInfo.LastQueryNode() = (TreeType*) this;
  traversalInfo.LastReferenceNode() = (TreeType*) this;
}

template<typename MetricType, typename TreeType>
inline force_inline double DTNNKMeansRules<MetricType, TreeType>::BaseCase(
    const size_t queryIndex,
    const size_t referenceIndex)
{
  if (prunedPoints[queryIndex])
    return 0.0; // Returning 0 shouldn't be a problem.

  // If we have already performed this base case, then do not perform it again.
  if ((lastQueryIndex == queryIndex) && (lastReferenceIndex == referenceIndex))
    return lastBaseCase;

  // Any base cases imply that we will get a result.
  visited[queryIndex] = true;

  // Calculate the distance.
  ++baseCases;
  const double distance = metric.Evaluate(dataset.col(queryIndex),
                                          centroids.col(referenceIndex));

  if (distance < upperBounds[queryIndex])
  {
    lowerBounds[queryIndex] = upperBounds[queryIndex];
    upperBounds[queryIndex] = distance;
    assignments[queryIndex] = (tree::TreeTraits<TreeType>::RearrangesDataset) ?
        oldFromNewCentroids[referenceIndex] : referenceIndex;
  }
  else if (distance < lowerBounds[queryIndex])
  {
    lowerBounds[queryIndex] = distance;
  }

  // Cache this information for the next time BaseCase() is called.
  lastQueryIndex = queryIndex;
  lastReferenceIndex = referenceIndex;
  lastBaseCase = distance;

  return distance;
}

template<typename MetricType, typename TreeType>
inline double DTNNKMeansRules<MetricType, TreeType>::Score(
    const size_t queryIndex,
    TreeType& /* referenceNode */)
{
  // If the query point has already been pruned, then don't recurse further.
  if (prunedPoints[queryIndex])
    return DBL_MAX;

  // No pruning at this level; we're not likely to encounter a single query
  // point with a reference node..
  return 0;
}

template<typename MetricType, typename TreeType>
inline double DTNNKMeansRules<MetricType, TreeType>::Score(
    TreeType& queryNode,
    TreeType& referenceNode)
{
  if (queryNode.Stat().StaticPruned() == true)
    return DBL_MAX;

  // Pruned() for the root node must never be set to size_t(-1).
  if (queryNode.Stat().Pruned() == size_t(-1))
  {
    queryNode.Stat().Pruned() = queryNode.Parent()->Stat().Pruned();
    queryNode.Stat().LowerBound() = queryNode.Parent()->Stat().LowerBound();
    queryNode.Stat().Owner() = queryNode.Parent()->Stat().Owner();
  }

  if (queryNode.Stat().Pruned() == centroids.n_cols)
    return DBL_MAX;

  // This looks a lot like the hackery used in NeighborSearchRules to avoid
  // distance computations.  We'll use the traversal info to see if a
  // parent-child or parent-parent prune is possible.
  const double queryParentDist = queryNode.ParentDistance();
  const double queryDescDist = queryNode.FurthestDescendantDistance();
  const double refParentDist = referenceNode.ParentDistance();
  const double refDescDist = referenceNode.FurthestDescendantDistance();
  const double lastScore = traversalInfo.LastScore();
  double adjustedScore;
  double score = 0.0;

  // We want to set adjustedScore to be the distance between the centroid of the
  // last query node and last reference node.  We will do this by adjusting the
  // last score.  In some cases, we can just use the last base case.
  if (tree::TreeTraits<TreeType>::FirstPointIsCentroid)
  {
    adjustedScore = traversalInfo.LastBaseCase();
  }
  else if (lastScore == 0.0) // Nothing we can do here.
  {
    adjustedScore = 0.0;
  }
  else
  {
    // The last score is equal to the distance between the centroids minus the
    // radii of the query and reference bounds along the axis of the line
    // between the two centroids.  In the best case, these radii are the
    // furthest descendant distances, but that is not always true.  It would
    // take too long to calculate the exact radii, so we are forced to use
    // MinimumBoundDistance() as a lower-bound approximation.
    const double lastQueryDescDist =
        traversalInfo.LastQueryNode()->MinimumBoundDistance();
    const double lastRefDescDist =
        traversalInfo.LastReferenceNode()->MinimumBoundDistance();
    adjustedScore = lastScore + lastQueryDescDist;
    adjustedScore = lastScore + lastRefDescDist;
  }

  // Assemble an adjusted score.  For nearest neighbor search, this adjusted
  // score is a lower bound on MinDistance(queryNode, referenceNode) that is
  // assembled without actually calculating MinDistance().  For furthest
  // neighbor search, it is an upper bound on
  // MaxDistance(queryNode, referenceNode).  If the traversalInfo isn't usable
  // then the node should not be pruned by this.
  if (traversalInfo.LastQueryNode() == queryNode.Parent())
  {
    const double queryAdjust = queryParentDist + queryDescDist;
    adjustedScore -= queryAdjust;
  }
  else if (traversalInfo.LastQueryNode() == &queryNode)
  {
    adjustedScore -= queryDescDist;
  }
  else
  {
    // The last query node wasn't this query node or its parent.  So we force
    // the adjustedScore to be such that this combination can't be pruned here,
    // because we don't really know anything about it.

    // It would be possible to modify this section to try and make a prune based
    // on the query descendant distance and the distance between the query node
    // and last traversal query node, but this case doesn't actually happen for
    // kd-trees or cover trees.
    adjustedScore = 0.0;
  }
  if (traversalInfo.LastReferenceNode() == referenceNode.Parent())
  {
    const double refAdjust = refParentDist + refDescDist;
    adjustedScore -= refAdjust;
  }
  else if (traversalInfo.LastReferenceNode() == &referenceNode)
  {
    adjustedScore -= refDescDist;
  }
  else
  {
    // The last reference node wasn't this reference node or its parent.  So we
    // force the adjustedScore to be such that this combination can't be pruned
    // here, because we don't really know anything about it.

    // It would be possible to modify this section to try and make a prune based
    // on the reference descendant distance and the distance between the
    // reference node and last traversal reference node, but this case doesn't
    // actually happen for kd-trees or cover trees.
    adjustedScore = 0.0;
  }

  // Now, check if we can prune.
  if (adjustedScore > queryNode.Stat().UpperBound())
  {
    if (!(tree::TreeTraits<TreeType>::FirstPointIsCentroid && score == 0.0))
    {
      // There isn't any need to set the traversal information because no
      // descendant combinations will be visited, and those are the only
      // combinations that would depend on the traversal information.
      if (adjustedScore < queryNode.Stat().LowerBound())
      {
        // If this might affect the lower bound, make it more exact.
        queryNode.Stat().LowerBound() = std::min(queryNode.Stat().LowerBound(),
            queryNode.MinDistance(&referenceNode));
        ++scores;
      }

      queryNode.Stat().Pruned() += referenceNode.NumDescendants();
      score = DBL_MAX;
    }
  }

  if (score != DBL_MAX)
  {
    // Get minimum and maximum distances.
    const math::Range distances = queryNode.RangeDistance(&referenceNode);

    score = distances.Lo();
    ++scores;
    if (distances.Lo() > queryNode.Stat().UpperBound())
    {
      // The reference node can own no points in this query node.  We may
      // improve the lower bound on pruned nodes, though.
      if (distances.Lo() < queryNode.Stat().LowerBound())
        queryNode.Stat().LowerBound() = distances.Lo();

      // This assumes that reference clusters don't appear elsewhere in the
      // tree.
      queryNode.Stat().Pruned() += referenceNode.NumDescendants();
      score = DBL_MAX;
    }
    else if (distances.Hi() < queryNode.Stat().UpperBound())
    {
      // Tighten upper bound.
      const double tighterBound =
          queryNode.MaxDistance(centroids.col(referenceNode.Descendant(0)));
      ++scores; // Count extra distance calculation.

      if (tighterBound <= queryNode.Stat().UpperBound())
      {
        // We can improve the best estimate.
        queryNode.Stat().UpperBound() = tighterBound;

        // Remember that our upper bound does correspond to a cluster centroid,
        // so it does correspond to a cluster.  We'll mark the cluster as the
        // owner, but note that the node is not truly owned unless
        // Stat().Pruned() is centroids.n_cols.
        queryNode.Stat().Owner() =
            (tree::TreeTraits<TreeType>::RearrangesDataset) ?
            oldFromNewCentroids[referenceNode.Descendant(0)] :
            referenceNode.Descendant(0);
      }
    }
  }

  // Is everything pruned?
  if (queryNode.Stat().Pruned() == centroids.n_cols - 1)
  {
    queryNode.Stat().Pruned() = centroids.n_cols; // Owner() is already set.
    return DBL_MAX;
  }

  // Set traversal information.
  traversalInfo.LastQueryNode() = &queryNode;
  traversalInfo.LastReferenceNode() = &referenceNode;
  traversalInfo.LastScore() = score;

  return score;
}

template<typename MetricType, typename TreeType>
inline double DTNNKMeansRules<MetricType, TreeType>::Rescore(
    const size_t /* queryIndex */,
    TreeType& /* referenceNode */,
    const double oldScore)
{
  // No rescoring (for now).
  return oldScore;
}

template<typename MetricType, typename TreeType>
inline double DTNNKMeansRules<MetricType, TreeType>::Rescore(
    TreeType& queryNode,
    TreeType& referenceNode,
    const double oldScore)
{
  if (oldScore == DBL_MAX)
    return DBL_MAX; // It's already pruned.

  // oldScore contains the minimum distance between queryNode and referenceNode.
  // In the time since Score() has been called, the upper bound *may* have
  // tightened.  If it has tightened enough, we may prune this node now.
  if (oldScore > queryNode.Stat().UpperBound())
  {
    // We may still be able to improve the lower bound on pruned nodes.
    if (oldScore < queryNode.Stat().LowerBound())
      queryNode.Stat().LowerBound() = oldScore;

    // This assumes that reference clusters don't appear elsewhere in the tree.
    queryNode.Stat().Pruned() += referenceNode.NumDescendants();
    return DBL_MAX;
  }

  // Also, check if everything has been pruned.
  if (queryNode.Stat().Pruned() == centroids.n_cols - 1)
  {
    queryNode.Stat().Pruned() = centroids.n_cols; // Owner() is already set.
    return DBL_MAX;
  }

  return oldScore;
}

} // namespace kmeans
} // namespace mlpack

#endif
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <qmath.h>

#include "qtextureglyphcache_p.h"

#include "private/qnumeric_p.h"
#include "private/qnativeimage_p.h"
#include "private/qfontengine_ft_p.h"

#ifndef QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH
#define QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH 256
#endif

QT_BEGIN_NAMESPACE

// #define CACHE_DEBUG

// returns the highest number closest to v, which is a power of 2
// NB! assumes 32 bit ints
int qt_next_power_of_two(int v)
{
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    ++v;
    return v;
}

void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
                                  const QFixedPoint *)
{
#ifdef CACHE_DEBUG
    printf("Populating with %d glyphs\n", numGlyphs);
    qDebug() << " -> current transformation: " << m_transform;
#endif

    m_current_fontengine = fontEngine;
    const int margin = glyphMargin();

    QHash<glyph_t, Coord> listItemCoordinates;
    int rowHeight = 0;

    // check each glyph for its metrics and get the required rowHeight.
    for (int i=0; i < numGlyphs; ++i) {
        const glyph_t glyph = glyphs[i];
        if (coords.contains(glyph))
            continue;
        if (listItemCoordinates.contains(glyph))
            continue;
        glyph_metrics_t metrics = fontEngine->boundingBox(glyph, m_transform);

#ifdef CACHE_DEBUG
        printf("(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
               glyph,
               metrics.width.toReal(),
               metrics.height.toReal(),
               metrics.xoff.toReal(),
               metrics.yoff.toReal(),
               metrics.x.toReal(),
               metrics.y.toReal());
#endif
        int glyph_width = metrics.width.ceil().toInt();
        int glyph_height = metrics.height.ceil().toInt();
        if (glyph_height == 0 || glyph_width == 0)
            continue;
        glyph_width += margin * 2 + 4;
        glyph_height += margin * 2 + 4;
        // align to 8-bit boundary
        if (m_type == QFontEngineGlyphCache::Raster_Mono)
            glyph_width = (glyph_width+7)&~7;

        Coord c = { 0, 0, // will be filled in later
                    glyph_width,
                    glyph_height, // texture coords
                    metrics.x.round().truncate(),
                    -metrics.y.truncate() }; // baseline for horizontal scripts

        listItemCoordinates.insert(glyph, c);
        rowHeight = qMax(rowHeight, glyph_height);
    }
    if (listItemCoordinates.isEmpty())
        return;

    rowHeight += margin * 2;
    if (isNull())
        createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, qt_next_power_of_two(rowHeight));

    // now actually use the coords and paint the wanted glyps into cache.
    QHash<glyph_t, Coord>::iterator iter = listItemCoordinates.begin();
    while (iter != listItemCoordinates.end()) {
        Coord c = iter.value();

        if (m_cx + c.w > m_w) {
            // no room on the current line, start new glyph strip
            m_cx = 0;
            m_cy = m_h;
        }
        if (m_cy + c.h > m_h) {
            int new_height = m_h*2;
            while (new_height < m_cy + c.h)
                new_height *= 2;
            // if no room in the current texture - realloc a larger texture
            resizeTextureData(m_w, new_height);
            m_h = new_height;
        }

        c.x = m_cx;
        c.y = m_cy;

        fillTexture(c, iter.key());
        coords.insert(iter.key(), c);

        if (m_cx + c.w > m_w) {
            m_cx = 0;
            m_cy += rowHeight;
        } else {
            // for the Mono case, glyph_width is 8-bit aligned,
            // and therefore so will m_cx
            m_cx += c.w;
        }
        ++iter;
    }

}

QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const
{
#if defined(Q_WS_X11)
    if (m_transform.type() > QTransform::TxTranslate) {
        QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_None;
        QImage::Format imageFormat = QImage::Format_Invalid;
        switch (m_type) {
        case Raster_RGBMask:
            format = QFontEngineFT::Format_A32;
            imageFormat = QImage::Format_RGB32;
            break;
        case Raster_A8:
            format = QFontEngineFT::Format_A8;
            imageFormat = QImage::Format_Indexed8;
            break;
        case Raster_Mono:
            format = QFontEngineFT::Format_Mono;
            imageFormat = QImage::Format_Mono;
            break;
        };

        QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine);
        QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform);

        if (gset && ft->loadGlyphs(gset, &g, 1, format)) {
            QFontEngineFT::Glyph *glyph = gset->glyph_data.value(g);
            const int bytesPerLine = (format == QFontEngineFT::Format_Mono ? ((glyph->width + 31) & ~31) >> 3
                               : (glyph->width + 3) & ~3);
            return QImage(glyph->data, glyph->width, glyph->height, bytesPerLine, imageFormat);
        }
    } else
#endif
    if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
        return m_current_fontengine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform);
    else
        return m_current_fontengine->alphaMapForGlyph(g, m_transform);

    return QImage();
}

/************************************************************************
 * QImageTextureGlyphCache
 */

void QImageTextureGlyphCache::resizeTextureData(int width, int height)
{
    m_image = m_image.copy(0, 0, width, height);
}

void QImageTextureGlyphCache::createTextureData(int width, int height)
{
    switch (m_type) {
    case QFontEngineGlyphCache::Raster_Mono:
        m_image = QImage(width, height, QImage::Format_Mono);
        break;
    case QFontEngineGlyphCache::Raster_A8: {
        m_image = QImage(width, height, QImage::Format_Indexed8);
        m_image.fill(0);
        QVector<QRgb> colors(256);
        QRgb *it = colors.data();
        for (int i=0; i<256; ++i, ++it)
            *it = 0xff000000 | i | (i<<8) | (i<<16);
        m_image.setColorTable(colors);
        break;   }
    case QFontEngineGlyphCache::Raster_RGBMask:
        m_image = QImage(width, height, QImage::Format_RGB32);
        break;
    }
}

int QImageTextureGlyphCache::glyphMargin() const
{
#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
    return 0;
#else
    return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
#endif
}

void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g)
{
    QImage mask = textureMapForGlyph(g);

#ifdef CACHE_DEBUG
    printf("fillTexture of %dx%d at %d,%d in the cache of %dx%d\n", c.w, c.h, c.x, c.y, m_image.width(), m_image.height());
    if (mask.width() > c.w || mask.height() > c.h) {
        printf("   ERROR; mask is bigger than reserved space! %dx%d instead of %dx%d\n", mask.width(), mask.height(), c.w,c.h);
        return;
    }
#endif

    if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
        QPainter p(&m_image);
        p.setCompositionMode(QPainter::CompositionMode_Source);
        p.fillRect(c.x, c.y, c.w, c.h, QColor(0,0,0,0)); // TODO optimize this
        p.drawImage(c.x, c.y, mask);
        p.end();
    } else if (m_type == QFontEngineGlyphCache::Raster_Mono) {
        if (mask.depth() > 1) {
            // TODO optimize this
            mask = mask.alphaChannel();
            mask.invertPixels();
            mask = mask.convertToFormat(QImage::Format_Mono);
        }

        int mw = qMin(mask.width(), c.w);
        int mh = qMin(mask.height(), c.h);
        uchar *d = m_image.bits();
        int dbpl = m_image.bytesPerLine();

        for (int y = 0; y < c.h; ++y) {
            uchar *dest = d + (c.y + y) *dbpl + c.x/8;

            if (y < mh) {
                uchar *src = mask.scanLine(y);
                for (int x = 0; x < c.w/8; ++x) {
                    if (x < (mw+7)/8)
                        dest[x] = src[x];
                    else
                        dest[x] = 0;
                }
            } else {
                for (int x = 0; x < c.w/8; ++x)
                    dest[x] = 0;
            }
        }
    } else { // A8
        int mw = qMin(mask.width(), c.w);
        int mh = qMin(mask.height(), c.h);
        uchar *d = m_image.bits();
        int dbpl = m_image.bytesPerLine();

        if (mask.depth() == 1) {
            for (int y = 0; y < c.h; ++y) {
                uchar *dest = d + (c.y + y) *dbpl + c.x;
                if (y < mh) {
                    uchar *src = (uchar *) mask.scanLine(y);
                    for (int x = 0; x < c.w; ++x) {
                        if (x < mw)
                            dest[x] = (src[x >> 3] & (1 << (7 - (x & 7)))) > 0 ? 255 : 0;
                    }
                }
            }
        } else if (mask.depth() == 8) {
            for (int y = 0; y < c.h; ++y) {
                uchar *dest = d + (c.y + y) *dbpl + c.x;
                if (y < mh) {
                    uchar *src = (uchar *) mask.scanLine(y);
                    for (int x = 0; x < c.w; ++x) {
                        if (x < mw)
                            dest[x] = src[x];
                    }
                }
            }
        }
    }

#ifdef CACHE_DEBUG
//     QPainter p(&m_image);
//     p.drawLine(
    QPoint base(c.x + glyphMargin(), c.y + glyphMargin() + c.baseLineY-1);
    if (m_image.rect().contains(base))
        m_image.setPixel(base, 255);
    m_image.save(QString::fromLatin1("cache-%1.png").arg(int(this)));
#endif
}

QT_END_NAMESPACE
<commit_msg>Fixed wasted space in the texture cache.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <qmath.h>

#include "qtextureglyphcache_p.h"

#include "private/qnumeric_p.h"
#include "private/qnativeimage_p.h"
#include "private/qfontengine_ft_p.h"

#ifndef QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH
#define QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH 256
#endif

QT_BEGIN_NAMESPACE

// #define CACHE_DEBUG

// returns the highest number closest to v, which is a power of 2
// NB! assumes 32 bit ints
int qt_next_power_of_two(int v)
{
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    ++v;
    return v;
}

void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
                                  const QFixedPoint *)
{
#ifdef CACHE_DEBUG
    printf("Populating with %d glyphs\n", numGlyphs);
    qDebug() << " -> current transformation: " << m_transform;
#endif

    m_current_fontengine = fontEngine;
    const int margin = glyphMargin();

    QHash<glyph_t, Coord> listItemCoordinates;
    int rowHeight = 0;

    // check each glyph for its metrics and get the required rowHeight.
    for (int i=0; i < numGlyphs; ++i) {
        const glyph_t glyph = glyphs[i];
        if (coords.contains(glyph))
            continue;
        if (listItemCoordinates.contains(glyph))
            continue;
        glyph_metrics_t metrics = fontEngine->boundingBox(glyph, m_transform);

#ifdef CACHE_DEBUG
        printf("(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
               glyph,
               metrics.width.toReal(),
               metrics.height.toReal(),
               metrics.xoff.toReal(),
               metrics.yoff.toReal(),
               metrics.x.toReal(),
               metrics.y.toReal());
#endif
        int glyph_width = metrics.width.ceil().toInt();
        int glyph_height = metrics.height.ceil().toInt();
        if (glyph_height == 0 || glyph_width == 0)
            continue;
        glyph_width += margin * 2 + 4;
        glyph_height += margin * 2 + 4;
        // align to 8-bit boundary
        if (m_type == QFontEngineGlyphCache::Raster_Mono)
            glyph_width = (glyph_width+7)&~7;

        Coord c = { 0, 0, // will be filled in later
                    glyph_width,
                    glyph_height, // texture coords
                    metrics.x.round().truncate(),
                    -metrics.y.truncate() }; // baseline for horizontal scripts

        listItemCoordinates.insert(glyph, c);
        rowHeight = qMax(rowHeight, glyph_height);
    }
    if (listItemCoordinates.isEmpty())
        return;

    rowHeight += margin * 2;
    if (isNull())
        createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, qt_next_power_of_two(rowHeight));

    // now actually use the coords and paint the wanted glyps into cache.
    QHash<glyph_t, Coord>::iterator iter = listItemCoordinates.begin();
    while (iter != listItemCoordinates.end()) {
        Coord c = iter.value();

        if (m_cx + c.w > m_w) {
            // no room on the current line, start new glyph strip
            m_cx = 0;
            m_cy += rowHeight;
        }
        if (m_cy + c.h > m_h) {
            int new_height = m_h*2;
            while (new_height < m_cy + c.h)
                new_height *= 2;
            // if no room in the current texture - realloc a larger texture
            resizeTextureData(m_w, new_height);
            m_h = new_height;
        }

        c.x = m_cx;
        c.y = m_cy;

        fillTexture(c, iter.key());
        coords.insert(iter.key(), c);

        if (m_cx + c.w > m_w) {
            m_cx = 0;
            m_cy += rowHeight;
        } else {
            // for the Mono case, glyph_width is 8-bit aligned,
            // and therefore so will m_cx
            m_cx += c.w;
        }
        ++iter;
    }

}

QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const
{
#if defined(Q_WS_X11)
    if (m_transform.type() > QTransform::TxTranslate) {
        QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_None;
        QImage::Format imageFormat = QImage::Format_Invalid;
        switch (m_type) {
        case Raster_RGBMask:
            format = QFontEngineFT::Format_A32;
            imageFormat = QImage::Format_RGB32;
            break;
        case Raster_A8:
            format = QFontEngineFT::Format_A8;
            imageFormat = QImage::Format_Indexed8;
            break;
        case Raster_Mono:
            format = QFontEngineFT::Format_Mono;
            imageFormat = QImage::Format_Mono;
            break;
        };

        QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine);
        QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform);

        if (gset && ft->loadGlyphs(gset, &g, 1, format)) {
            QFontEngineFT::Glyph *glyph = gset->glyph_data.value(g);
            const int bytesPerLine = (format == QFontEngineFT::Format_Mono ? ((glyph->width + 31) & ~31) >> 3
                               : (glyph->width + 3) & ~3);
            return QImage(glyph->data, glyph->width, glyph->height, bytesPerLine, imageFormat);
        }
    } else
#endif
    if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
        return m_current_fontengine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform);
    else
        return m_current_fontengine->alphaMapForGlyph(g, m_transform);

    return QImage();
}

/************************************************************************
 * QImageTextureGlyphCache
 */

void QImageTextureGlyphCache::resizeTextureData(int width, int height)
{
    m_image = m_image.copy(0, 0, width, height);
}

void QImageTextureGlyphCache::createTextureData(int width, int height)
{
    switch (m_type) {
    case QFontEngineGlyphCache::Raster_Mono:
        m_image = QImage(width, height, QImage::Format_Mono);
        break;
    case QFontEngineGlyphCache::Raster_A8: {
        m_image = QImage(width, height, QImage::Format_Indexed8);
        m_image.fill(0);
        QVector<QRgb> colors(256);
        QRgb *it = colors.data();
        for (int i=0; i<256; ++i, ++it)
            *it = 0xff000000 | i | (i<<8) | (i<<16);
        m_image.setColorTable(colors);
        break;   }
    case QFontEngineGlyphCache::Raster_RGBMask:
        m_image = QImage(width, height, QImage::Format_RGB32);
        break;
    }
}

int QImageTextureGlyphCache::glyphMargin() const
{
#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
    return 0;
#else
    return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
#endif
}

void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g)
{
    QImage mask = textureMapForGlyph(g);

#ifdef CACHE_DEBUG
    printf("fillTexture of %dx%d at %d,%d in the cache of %dx%d\n", c.w, c.h, c.x, c.y, m_image.width(), m_image.height());
    if (mask.width() > c.w || mask.height() > c.h) {
        printf("   ERROR; mask is bigger than reserved space! %dx%d instead of %dx%d\n", mask.width(), mask.height(), c.w,c.h);
        return;
    }
#endif

    if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
        QPainter p(&m_image);
        p.setCompositionMode(QPainter::CompositionMode_Source);
        p.fillRect(c.x, c.y, c.w, c.h, QColor(0,0,0,0)); // TODO optimize this
        p.drawImage(c.x, c.y, mask);
        p.end();
    } else if (m_type == QFontEngineGlyphCache::Raster_Mono) {
        if (mask.depth() > 1) {
            // TODO optimize this
            mask = mask.alphaChannel();
            mask.invertPixels();
            mask = mask.convertToFormat(QImage::Format_Mono);
        }

        int mw = qMin(mask.width(), c.w);
        int mh = qMin(mask.height(), c.h);
        uchar *d = m_image.bits();
        int dbpl = m_image.bytesPerLine();

        for (int y = 0; y < c.h; ++y) {
            uchar *dest = d + (c.y + y) *dbpl + c.x/8;

            if (y < mh) {
                uchar *src = mask.scanLine(y);
                for (int x = 0; x < c.w/8; ++x) {
                    if (x < (mw+7)/8)
                        dest[x] = src[x];
                    else
                        dest[x] = 0;
                }
            } else {
                for (int x = 0; x < c.w/8; ++x)
                    dest[x] = 0;
            }
        }
    } else { // A8
        int mw = qMin(mask.width(), c.w);
        int mh = qMin(mask.height(), c.h);
        uchar *d = m_image.bits();
        int dbpl = m_image.bytesPerLine();

        if (mask.depth() == 1) {
            for (int y = 0; y < c.h; ++y) {
                uchar *dest = d + (c.y + y) *dbpl + c.x;
                if (y < mh) {
                    uchar *src = (uchar *) mask.scanLine(y);
                    for (int x = 0; x < c.w; ++x) {
                        if (x < mw)
                            dest[x] = (src[x >> 3] & (1 << (7 - (x & 7)))) > 0 ? 255 : 0;
                    }
                }
            }
        } else if (mask.depth() == 8) {
            for (int y = 0; y < c.h; ++y) {
                uchar *dest = d + (c.y + y) *dbpl + c.x;
                if (y < mh) {
                    uchar *src = (uchar *) mask.scanLine(y);
                    for (int x = 0; x < c.w; ++x) {
                        if (x < mw)
                            dest[x] = src[x];
                    }
                }
            }
        }
    }

#ifdef CACHE_DEBUG
//     QPainter p(&m_image);
//     p.drawLine(
    QPoint base(c.x + glyphMargin(), c.y + glyphMargin() + c.baseLineY-1);
    if (m_image.rect().contains(base))
        m_image.setPixel(base, 255);
    m_image.save(QString::fromLatin1("cache-%1.png").arg(int(this)));
#endif
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>#include "common/BenchmarkRunner.h"
#include "common/CommandLineConfiguration.h"
#include "common/MpiGuard.h"
#include "common/MpiHelper.h"
#include "matrix/MatrixHelper.h"
#include "matrix/Matrix.h"

#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>

using namespace std;

void exportClusterConfiguration(const string& filename, BenchmarkResult& result)
{
    fstream file(filename, fstream::out);
    if (!file.is_open())
    {
        cerr << "ERROR: Could not write "<<filename<<endl;
        exit(1);
    }
    file << result;
    file.close();
}

BenchmarkResult importClusterConfiguration(const string& filename)
{
    fstream file(filename, fstream::in);
    if (!file.is_open())
    {
        cerr << "ERROR: Could not read "<<filename<<endl;
        exit(1);
    }
    BenchmarkResult result;
    file >> result;
    file.close();
    if (result.size() != MpiHelper::numberOfNodes())
    {
        cerr << "ERROR: Number of nodes does not match configured number of nodes" <<endl;
        exit(1);
    }
    return result;
}

void silenceOutputStreams(bool keepErrorStreams = false)
{
    cout.rdbuf(nullptr);

    if (!keepErrorStreams)
    {
        cerr.rdbuf(nullptr);
        clog.rdbuf(nullptr);
    }
}

void benchmarkWith(const Configuration& config)
{
    BenchmarkRunner runner(config);
    BenchmarkResult nodeWeights;

    ofstream timeFile(config.timeOutputFilename(), ios::app);

    if (!timeFile.is_open())
        throw runtime_error("Failed to open file \"" + config.timeOutputFilename() + "\"");

    if (config.shouldExportConfiguration() || !config.shouldImportConfiguration())
    {
        cout << "Calculating node weights" <<endl;
        nodeWeights = runner.benchmarkIndividualNodes();
        cout << "Weighted " << endl << nodeWeights;
    }
    if (config.shouldExportConfiguration())
    {
        cout << "Exporting node weights" <<endl;
        exportClusterConfiguration(config.exportConfigurationFilename(), nodeWeights);
    }
    if (config.shouldImportConfiguration())
    {
        cout << "Importing node weights" <<endl;
        nodeWeights = importClusterConfiguration(config.importConfigurationFilename());
    }
    if (!config.shouldSkipBenchmark())
    {
        cout << "Running benchmark" <<endl;
        auto clusterResults = runner.runBenchmark(nodeWeights);
        cout << "Measured Times: µs" << endl;

        for (const auto& measurement : clusterResults)
        {
            cout << "\t" << measurement.count() << endl;

            if (MpiHelper::isMaster())
                timeFile << measurement.count() << endl;
        }
    }
}

int main(int argc, char** argv)
{
    // used to ensure MPI::Finalize is called on exit of the application
    MpiGuard guard(argc, argv);

    try
    {
        CommandLineConfiguration config(argc, argv);

        if (config.shouldPrintHelp())
        {
            config.printHelp();
            return 0;
        }

        if (!config.shouldBeVerbose() && (config.shouldBeQuiet() || !MpiHelper::isMaster()))
            silenceOutputStreams(true);

        cout << config << endl;

        benchmarkWith(config);
    }
    catch (const boost::program_options::error& e)
    {
        CommandLineConfiguration::printHelp();
        cerr << e.what() << endl;
        return 1;
    }
    catch (const logic_error& e)
    {
        cerr << "ERROR: " << e.what() << endl;
        return 1;
    }
    catch (const exception& e)
    {
        cerr << "FATAL: " << e.what() << endl;
        return 1;
    }
    catch (...)
    {
        cerr << "FATAL ERROR of unknown type." << endl;
        return 1;
    }

    return 0;
}

<commit_msg>only master creates time-output-file<commit_after>#include "common/BenchmarkRunner.h"
#include "common/CommandLineConfiguration.h"
#include "common/MpiGuard.h"
#include "common/MpiHelper.h"
#include "matrix/MatrixHelper.h"
#include "matrix/Matrix.h"

#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>

using namespace std;

void exportClusterConfiguration(const string& filename, BenchmarkResult& result)
{
    fstream file(filename, fstream::out);
    if (!file.is_open())
    {
        cerr << "ERROR: Could not write "<<filename<<endl;
        exit(1);
    }
    file << result;
    file.close();
}

BenchmarkResult importClusterConfiguration(const string& filename)
{
    fstream file(filename, fstream::in);
    if (!file.is_open())
    {
        cerr << "ERROR: Could not read "<<filename<<endl;
        exit(1);
    }
    BenchmarkResult result;
    file >> result;
    file.close();
    if (result.size() != MpiHelper::numberOfNodes())
    {
        cerr << "ERROR: Number of nodes does not match configured number of nodes" <<endl;
        exit(1);
    }
    return result;
}

void silenceOutputStreams(bool keepErrorStreams = false)
{
    cout.rdbuf(nullptr);

    if (!keepErrorStreams)
    {
        cerr.rdbuf(nullptr);
        clog.rdbuf(nullptr);
    }
}

void benchmarkWith(const Configuration& config)
{
    BenchmarkRunner runner(config);
    BenchmarkResult nodeWeights;

    ofstream timeFile;

    if (MpiHelper::isMaster())
    {
        timeFile.open(config.timeOutputFilename(), ios::app);

        if (!timeFile.is_open())
            throw runtime_error("Failed to open file \"" + config.timeOutputFilename() + "\"");
    }

    if (config.shouldExportConfiguration() || !config.shouldImportConfiguration())
    {
        cout << "Calculating node weights" <<endl;
        nodeWeights = runner.benchmarkIndividualNodes();
        cout << "Weighted " << endl << nodeWeights;
    }
    if (config.shouldExportConfiguration())
    {
        cout << "Exporting node weights" <<endl;
        exportClusterConfiguration(config.exportConfigurationFilename(), nodeWeights);
    }
    if (config.shouldImportConfiguration())
    {
        cout << "Importing node weights" <<endl;
        nodeWeights = importClusterConfiguration(config.importConfigurationFilename());
    }
    if (!config.shouldSkipBenchmark())
    {
        cout << "Running benchmark" <<endl;
        auto clusterResults = runner.runBenchmark(nodeWeights);
        cout << "Measured Times: µs" << endl;

        for (const auto& measurement : clusterResults)
        {
            cout << "\t" << measurement.count() << endl;

            if (MpiHelper::isMaster())
                timeFile << measurement.count() << endl;
        }
    }
}

int main(int argc, char** argv)
{
    // used to ensure MPI::Finalize is called on exit of the application
    MpiGuard guard(argc, argv);

    try
    {
        CommandLineConfiguration config(argc, argv);

        if (config.shouldPrintHelp())
        {
            config.printHelp();
            return 0;
        }

        if (!config.shouldBeVerbose() && (config.shouldBeQuiet() || !MpiHelper::isMaster()))
            silenceOutputStreams(true);

        cout << config << endl;

        benchmarkWith(config);
    }
    catch (const boost::program_options::error& e)
    {
        CommandLineConfiguration::printHelp();
        cerr << e.what() << endl;
        return 1;
    }
    catch (const logic_error& e)
    {
        cerr << "ERROR: " << e.what() << endl;
        return 1;
    }
    catch (const exception& e)
    {
        cerr << "FATAL: " << e.what() << endl;
        return 1;
    }
    catch (...)
    {
        cerr << "FATAL ERROR of unknown type." << endl;
        return 1;
    }

    return 0;
}

<|endoftext|>


<commit_before>#include "limit_quote.h"

void Limit_quote::debug() const
{
    std::cout << "data members of this class:\n"
              << "max_qty= " << this->max_qty << " "
              << "discount= " << this->discount<< " \n";
}
<commit_msg>Delete limit_quote.cpp<commit_after><|endoftext|>