Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> unordered_map<int,int> vs std::map<int,int>, что быстрее 
:(
    Опции темы
borisbn
Дата 10.11.2011, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Привет всем.
Решил сравнить по скорости std::map и boost::unordered_map.
Почему-то думал, что для такого map< int, int > stl должен быть быстрее, т.к. он ведёт поиск в отсортированном дереве (или сбалансированном), а boost::unordered_map - в обычном, и хэш по int должен быть сам int, но оказалось всё с точностью до наоборот (unordered_map прилично быстрее). Объясните, пожалуйста, почему. 

вот код:
Код

std::map< int, int > std_m;
boost::unordered_map< int, int > boost_m;
std::vector< int > values;

const int N = 1000000;
int main()
{
    int t1, t2;
    for ( int i = 0; i < N; i++ )
        values.push_back( rand() * rand() );
    std::cout << "insert:" << std::endl;
    for ( int k = 0; k < 5; k++ ) {
        t1 = clock();
        for ( int i = 0; i < N; i++ )
            std_m[ values[ i ] ] = i;
        t2 = clock();
        std::cout << "std   : " << std::setw( 8 ) << (t2 - t1) / (double)CLOCKS_PER_SEC * 1000 << " ms." << std::endl;

        t1 = clock();
        for ( int i = 0; i < N; i++ )
            boost_m[ values[ i ] ] = i;
        t2 = clock();
        std::cout << "boost : " << std::setw( 8 ) << (t2 - t1) / (double)CLOCKS_PER_SEC * 1000 << " ms." << std::endl;
    }

    std::vector< int > temp( N );

    std::cout << std::endl << "size = " << std_m.size() << std::endl << std::endl;

    std::cout << "find[] :" << std::endl;
    for ( int k = 0; k < 5; k++ ) {
        t1 = clock();
        for ( int i = 0; i < N; i++ )
            temp[ i ] = std_m[ values[ i ] ];
        t2 = clock();
        std::cout << "std   : " << std::setw( 8 ) << (t2 - t1) / (double)CLOCKS_PER_SEC * 1000 << " ms. control : " << temp[ 42 ] << std::endl;

        t1 = clock();
        for ( int i = 0; i < N; i++ )
            temp[ i ] = boost_m[ values[ i ] ];
        t2 = clock();
        std::cout << "boost : " << std::setw( 8 ) << (t2 - t1) / (double)CLOCKS_PER_SEC * 1000 << " ms. control : " << temp[ 42 ] << std::endl;
    }
    std::cout << std::endl;
    std::cout << "find.find :" << std::endl;
    for ( int k = 0; k < 5; k++ ) {
        t1 = clock();
        for ( int i = 0; i < N; i++ )
            temp[ i ] = std_m.find( values[ i ] )->second;
        t2 = clock();
        std::cout << "std   : " << std::setw( 8 ) << (t2 - t1) / (double)CLOCKS_PER_SEC * 1000 << " ms. control : " << temp[ 42 ] << std::endl;

        t1 = clock();
        for ( int i = 0; i < N; i++ )
            temp[ i ] = boost_m.find( values[ i ] )->second;
        t2 = clock();
        std::cout << "boost : " << std::setw( 8 ) << (t2 - t1) / (double)CLOCKS_PER_SEC * 1000 << " ms. control : " << temp[ 42 ] << std::endl;
    }
}

http://liveworkspace.org/code/b5b3d5f77cb5...09535c8e83dc5d8

Вот вывод:
Цитата

insert:
std   :      922 ms.
boost :      500 ms.
std   :      782 ms.
boost :      109 ms.
std   :      781 ms.
boost :      110 ms.
std   :      765 ms.
boost :      110 ms.
std   :      765 ms.
boost :      110 ms.

size = 994626

find[] :
std   :      750 ms. control : 42
boost :       94 ms. control : 42
std   :      750 ms. control : 42
boost :       94 ms. control : 42
std   :      750 ms. control : 42
boost :       93 ms. control : 42
std   :      750 ms. control : 42
boost :       94 ms. control : 42
std   :      766 ms. control : 42
boost :       78 ms. control : 42

find.find :
std   :      750 ms. control : 42
boost :       62 ms. control : 42
std   :      750 ms. control : 42
boost :       47 ms. control : 42
std   :      750 ms. control : 42
boost :       47 ms. control : 42
std   :      750 ms. control : 42
boost :       63 ms. control : 42
std   :      750 ms. control : 42
boost :       47 ms. control : 42


stl - из состава minGW 4.4.0 (который в свою очередь из состава QtSDK)
boost - с офф.сайта. версия 1.47.0 

P.S. Может ещё кто подскажет, почему поиск функцией find быстрее поиска оператором []...

Спасибо.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 10.11.2011, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



borisbn, дополни свой тест еще std::unordered_map, плиз.
PM WWW   Вверх
borisbn
Дата 10.11.2011, 16:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



boostcoder,
Цитата(borisbn @  10.11.2011,  15:53 Найти цитируемый пост)
stl - из состава minGW 4.4.0


Всё никак руки не доходят скачать твой minGW (с поддержкой 0x11) и прикрутить его к QtCreator'у.
Кста, может кто-нибудь это делал ?
Тогда подскажите как.



--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
Alca
Дата 10.11.2011, 16:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 7
Всего: 50



Цитата

Тогда подскажите как.

Tools -> Options -> Qt4
Tools -> Options -> Tool Chains

Это сообщение отредактировал(а) Alca - 10.11.2011, 17:00


--------------------
PM WWW ICQ Skype Jabber   Вверх
borisbn
Дата 10.11.2011, 17:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Alca, там указывается, где расположен qmake, а не minGW


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 10.11.2011, 18:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



borisbn, если я ничего не путаю, то в 4.4.0 уже есть std::unordered*

Добавлено через 4 минуты
Цитата(borisbn @  10.11.2011,  16:52 Найти цитируемый пост)
Кста, может кто-нибудь это делал ?

user posted image
PM WWW   Вверх
borisbn
Дата 10.11.2011, 20:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Итак.
1. Сделал std::unordered_map в minGW 4.4.0
Вот код
http://liveworkspace.org/code/bc7579812ea4...a364184425dcffd
Вот рез-ты (на моей машине)
Цитата

insert:
std   :      937 ms.
boost :      516 ms.
std_u :      484 ms.
std   :      735 ms.
boost :      125 ms.
std_u :      125 ms.
std   :      750 ms.
boost :      109 ms.
std_u :      125 ms.
std   :      750 ms.
boost :      109 ms.
std_u :      125 ms.
std   :      750 ms.
boost :      125 ms.
std_u :      125 ms.

size = 994626

find[] :
std   :      735 ms. control : 42
boost :       94 ms. control : 42
std_u :       78 ms. control : 42
std   :      750 ms. control : 42
boost :       93 ms. control : 42
std_u :       79 ms. control : 42
std   :      750 ms. control : 42
boost :       78 ms. control : 42
std_u :       78 ms. control : 42
std   :      750 ms. control : 42
boost :       94 ms. control : 42
std_u :       78 ms. control : 42
std   :      750 ms. control : 42
boost :       78 ms. control : 42
std_u :       78 ms. control : 42

find.find :
std   :      812 ms. control : 42
boost :       63 ms. control : 42
std_u :       47 ms. control : 42
std   :      735 ms. control : 42
boost :       62 ms. control : 42
std_u :       63 ms. control : 42
std   :      750 ms. control : 42
boost :       47 ms. control : 42
std_u :       62 ms. control : 42
std   :      750 ms. control : 42
boost :       63 ms. control : 42
std_u :       62 ms. control : 42
std   :      750 ms. control : 42
boost :       47 ms. control : 42
std_u :       63 ms. control : 42


2. Судя по всему что std::, что boost:: unordered_map ведут себя одинакого
3. Мне всё равно непонятно, почему unordered быстрее "ordered"
4. А что с вопросом про operator[] vs unordered_map::find() ?
5. 2 boostcoder: что отсюда (http://code.google.com/p/mingw-builds/downloads/list) из этого списка
user posted image
мне поставить, чтобы: 1) была стабильная версия 2) чтобы был только Си++ (мне не нужен ни objC, ни fortran). Спасибо.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 10.11.2011, 20:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(borisbn @  10.11.2011,  20:20 Найти цитируемый пост)
boostcoder: что отсюда (http://code.google.com/p/mingw-builds/downloads/list) из этого списка мне поставить, чтобы: 1) была стабильная версия 2) чтобы был только Си++ (мне не нужен ни objC, ни fortran).

описание для кого писал? smile 
Цитата

Какую сборку выбрать? - Все просто!

Если Вам нужна стабильная сборка, ищите сборки в именах которых присутствует "release". Например: 4.6.1-release-20110828 означает, что это сборка GCC версии 4.6.1, стабильная, дата сборки 20110828. Если в имени сборки присутствует "FINAL", это означает, что это последняя сборка этой версии компилятора, и, как правило - лучшая. Если суффикс равен "dwarf2" - значит этот компилятор реализует исключения используя DWARF2 технологию. Иначе SJLJ.

без фортрана и обжектив-си сборок нет. чтоб не плодить процесс сборки и архивы.

так что рекомендую эту:
4.6.2-release-c,c++,objc,objc++,fortran-dwarf
zip - http://mingw-builds.googlecode.com/files/m...rtran-dwarf.zip
7z - http://mingw-builds.googlecode.com/files/m...ortran-dwarf.7z
PM WWW   Вверх
Леопольд
Дата 10.11.2011, 20:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(borisbn @  10.11.2011,  20:20 Найти цитируемый пост)
4. А что с вопросом про operator[] vs unordered_map::find() ?
Тестировался оптимизированный код?


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
borisbn
Дата 10.11.2011, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



boostcoder, премного благодарен. Скачаю, установлю, настрою - отпишусь.
А если, всё-таки, "вернуться к нашим баранам"... Что по теме ?
Почему unordered быстрее ordered ?

Цитата(Леопольд @  10.11.2011,  20:41 Найти цитируемый пост)
Тестировался оптимизированный код?

Честно говоря, просто выбрал тип сборки Release...
Сейчас посмотрел сгенерённый qmake'ом Makefile.Release:
Цитата

...
CFLAGS        = -O2 -Wall $(DEFINES)
...

больше ничего относящегося к компилятору не нашёл. Нужно будет - могу весь Makefile выложить


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 10.11.2011, 21:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(borisbn @  10.11.2011,  21:22 Найти цитируемый пост)
Почему unordered быстрее ordered ?

тут неплохо описывается: http://lanzkron.wordpress.com/2010/06/02/o...tz-for-klutzes/

Добавлено через 14 минут и 27 секунд
borisbn, так ты допишешь в тест std::unordered_map?
PM WWW   Вверх
borisbn
Дата 10.11.2011, 22:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(boostcoder @  10.11.2011,  21:37 Найти цитируемый пост)
так ты допишешь в тест std::unordered_map?


Цитата(borisbn @  10.11.2011,  20:20 Найти цитируемый пост)
1. Сделал std::unordered_map в minGW 4.4.0
Вот код
http://liveworkspace.org/code/bc7579812ea4...a364184425dcffd
Вот рез-ты (на моей машине)


Цитата(borisbn @  10.11.2011,  21:22 Найти цитируемый пост)
Скачаю, установлю, настрою - отпишусь.

скачал, установил, настроил - работает  smile 
правда долго тупил, что дать креатору в качестве компилятора - c++.exe, g++.exe, gcc.exe, i686-pc-mingw32-c++.exe, i686-pc-mingw32-g++.exe, i686-pc-mingw32-gcc-4.6.2.exe или i686-pc-mingw32-gcc.exe...
в общем остановился на g++.

Цитата(boostcoder @  10.11.2011,  21:37 Найти цитируемый пост)
тут неплохо описывается:

Да. интересно. Так что, получается в unordered_map используется не дерево, а тупо массив, а мой ключ переводится в обычный индекс...
хммм. интересно...


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 10.11.2011, 22:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(borisbn @  10.11.2011,  22:15 Найти цитируемый пост)
в общем остановился на g++.

угу.

Цитата(borisbn @  10.11.2011,  22:15 Найти цитируемый пост)
Так что, получается в unordered_map используется не дерево, а тупо массив, а мой ключ переводится в обычный индекс...

я этого тоже не понял. мне кажется это не верный вывод. наверняка автор что-то напутал... но разобраться в исходниках std::unordered_map ой как не просто.

Цитата(borisbn @  10.11.2011,  22:15 Найти цитируемый пост)

Цитата(boostcoder @  10.11.2011,  21:37 )
так ты допишешь в тест std::unordered_map?


Цитата(borisbn @  10.11.2011,  20:20 )
Сделал std::unordered_map в minGW 4.4.0
Вот код http://liveworkspace.org/code/bc7579812ea4...a364184425dcffd
Вот рез-ты (на моей машине)

как-то я не заметил smile

Добавлено через 1 минуту и 18 секунд
Цитата(borisbn @  10.11.2011,  20:20 Найти цитируемый пост)
Сделал std::unordered_map в minGW 4.4.0

а с 4.6.2 результаты такие же? а то со времен 4.4.0 многое изменилось.

Добавлено через 2 минуты и 44 секунды
мои результаты:
Цитата

insert:
std   :      960 ms.
boost :      650 ms.
std_u :      450 ms.
std   :      850 ms.
boost :      250 ms.
std_u :      160 ms.
std   :      840 ms.
boost :      240 ms.
std_u :      160 ms.
std   :      860 ms.
boost :      250 ms.
std_u :      160 ms.
std   :      840 ms.
boost :      250 ms.
std_u :      160 ms.

size = 999811

find[] :
std   :      840 ms. control : 42
boost :      240 ms. control : 42
std_u :      160 ms. control : 42
std   :      840 ms. control : 42
boost :      240 ms. control : 42
std_u :      160 ms. control : 42
std   :      840 ms. control : 42
boost :      240 ms. control : 42
std_u :      160 ms. control : 42
std   :      830 ms. control : 42
boost :      250 ms. control : 42
std_u :      150 ms. control : 42
std   :      840 ms. control : 42
boost :      250 ms. control : 42
std_u :      150 ms. control : 42

find.find :
std   :      850 ms. control : 42
boost :      250 ms. control : 42
std_u :      160 ms. control : 42
std   :      830 ms. control : 42
boost :      240 ms. control : 42
std_u :      160 ms. control : 42
std   :      840 ms. control : 42
boost :      250 ms. control : 42
std_u :      160 ms. control : 42
std   :      870 ms. control : 42
boost :      260 ms. control : 42
std_u :      170 ms. control : 42
std   :      830 ms. control : 42
boost :      250 ms. control : 42
std_u :      160 ms. control : 42

стандартный умап однозначно рвет всех. это не может не радовать smile
PM WWW   Вверх
borisbn
Дата 10.11.2011, 22:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



вот на 4.6.2
Цитата

insert:
std   :      906 ms.
boost :      469 ms.
std_u :      469 ms.
std   :      750 ms.
boost :      125 ms.
std_u :      125 ms.
std   :      750 ms.
boost :      109 ms.
std_u :      125 ms.
std   :      750 ms.
boost :      125 ms.
std_u :      110 ms.
std   :      750 ms.
boost :      125 ms.
std_u :      125 ms.

size = 994626

find[] :
std   :      750 ms. control : 42
boost :       78 ms. control : 42
std_u :       62 ms. control : 42
std   :      750 ms. control : 42
boost :       78 ms. control : 42
std_u :       63 ms. control : 42
std   :      750 ms. control : 42
boost :       78 ms. control : 42
std_u :       63 ms. control : 42
std   :      750 ms. control : 42
boost :       78 ms. control : 42
std_u :       62 ms. control : 42
std   :      750 ms. control : 42
boost :       78 ms. control : 42
std_u :       63 ms. control : 42

find.find :
std   :      750 ms. control : 42
boost :       47 ms. control : 42
std_u :       78 ms. control : 42
std   :      734 ms. control : 42
boost :       63 ms. control : 42
std_u :       62 ms. control : 42
std   :      735 ms. control : 42
boost :       62 ms. control : 42
std_u :       63 ms. control : 42
std   :      750 ms. control : 42
boost :       46 ms. control : 42
std_u :       63 ms. control : 42
std   :      750 ms. control : 42
boost :       47 ms. control : 42
std_u :       78 ms. control : 42


относительно 4.4.0 поменялось только время получения элемента оператором [] - оно теперь равно find'овскому ( что также не может не радовать smile ). Так что вопрос по оператору [] снимается

А ещё не может не радовать, что теперь exe-шник не требует minGW-шных и libc-шных dll-ек

Цитата(boostcoder @  10.11.2011,  22:26 Найти цитируемый пост)
но разобраться в исходниках std::unordered_map ой как не просто

я попытался и бросил - unordered_map наследуется от Hashtable, который, в свою очередь наследуется от Rehash_base, Hash_code_base, Map_base и Equality_base... бррррррр.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 10.11.2011, 23:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(borisbn @  10.11.2011,  22:47 Найти цитируемый пост)
А ещё не может не радовать, что теперь exe-шник не требует minGW-шных и libc-шных dll-ек

я в своих сборках использую CRT проекта wingw-w64, что в свою очередь делает библиотеки собранные стандартным MinGW, несовместимыми с моей сборкой. так, к примеру, моей сборкой не получится слинковать QtSDK. Qt нужно пересобирать.
но я такой путь выбрал не зря. во первых - mingw.org предоставляет CRT только для 32-ух битных компиляторов. во вторых - проект очень слабо развивается, и, как признаются сами авторы, не имеет смысла на продолжение. он не будет переписан для 64-ех битных компиляторов.

по поводу же пересборки всего, что предполагается юзать с моей сборкой MinGW - я работаю над проектом, который будет включать в себя кучу предкомпилированных либ, которые можно будет установить и обновлять используя онлайн-инсталлятор.

Добавлено через 2 минуты и 22 секунды
ах да. об этом я уже писал тут smile 
http://forum.vingrad.ru/index.php?showtopi...t&p=2403408

Добавлено через 11 минут и 46 секунд
Цитата(boostcoder @  10.11.2011,  23:05 Найти цитируемый пост)
так, к примеру, моей сборкой не получится слинковать QtSDK. Qt нужно пересобирать.

если же использовать sjlj сборку - то слинкуется. но будет падать по сегфолту.
PM WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0649 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.