<commit_before>/*
Copyright (c) 2015-2017 Advanced Micro Devices, Inc. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "hip/hip_runtime.h"
#include "hip_hcc.h"
#include "trace_helper.h"
#include "device_util.h"

//-------------------------------------------------------------------------------------------------
//Devices
//-------------------------------------------------------------------------------------------------
// TODO - does this initialize HIP runtime?
hipError_t hipGetDevice(int *deviceId)
{
    HIP_INIT_API(deviceId);

    hipError_t e = hipSuccess;

    auto ctx = ihipGetTlsDefaultCtx();

    if(deviceId != nullptr){
        if (ctx == nullptr) {
            e = hipErrorInvalidDevice; // TODO, check error code.
            *deviceId = -1;
        } else {
            *deviceId = ctx->getDevice()->_deviceId;
        }
    }else{
        e = hipErrorInvalidValue;
    }

    return ihipLogStatus(e);
}

// TODO - does this initialize HIP runtime?
hipError_t ihipGetDeviceCount(int *count)
{
    hipError_t e = hipSuccess;

    if(count != nullptr) {
        *count = g_deviceCnt;

        if (*count > 0) {
            e = ihipLogStatus(hipSuccess);
        } else {
            e = ihipLogStatus(hipErrorNoDevice);
        }
    } else {
        e = ihipLogStatus(hipErrorInvalidValue);
    }
    return e;
}

hipError_t hipGetDeviceCount(int *count)
{
    HIP_INIT_API(count);
    return ihipGetDeviceCount(count);
}

hipError_t hipDeviceSetCacheConfig(hipFuncCache_t cacheConfig)
{
    HIP_INIT_API(cacheConfig);

    // Nop, AMD does not support variable cache configs.

    return ihipLogStatus(hipSuccess);
}

hipError_t hipDeviceGetCacheConfig(hipFuncCache_t *cacheConfig)
{
    HIP_INIT_API(cacheConfig);

    if(cacheConfig == nullptr) {
        return ihipLogStatus(hipErrorInvalidValue);
    }

    *cacheConfig = hipFuncCachePreferNone;

    return ihipLogStatus(hipSuccess);
}

hipError_t hipDeviceGetLimit (size_t *pValue, hipLimit_t limit)
{
    HIP_INIT_API(pValue, limit);
    if(pValue == nullptr) {
        return ihipLogStatus(hipErrorInvalidValue);
    }
    if(limit == hipLimitMallocHeapSize) {
        *pValue = (size_t)SIZE_OF_HEAP;
        return ihipLogStatus(hipSuccess);
    }else{
        return ihipLogStatus(hipErrorUnsupportedLimit);
    }
}

hipError_t hipFuncSetCacheConfig (hipFuncCache_t cacheConfig)
{
    HIP_INIT_API(cacheConfig);

    // Nop, AMD does not support variable cache configs.

    return ihipLogStatus(hipSuccess);
}

hipError_t hipDeviceSetSharedMemConfig (hipSharedMemConfig config)
{
    HIP_INIT_API(config);

    // Nop, AMD does not support variable shared mem configs.

    return ihipLogStatus(hipSuccess);
}

hipError_t hipDeviceGetSharedMemConfig (hipSharedMemConfig *pConfig)
{
    HIP_INIT_API(pConfig);

    *pConfig = hipSharedMemBankSizeFourByte;

    return ihipLogStatus(hipSuccess);
}

hipError_t hipSetDevice(int deviceId)
{
    HIP_INIT_API(deviceId);
    if ((deviceId < 0) || (deviceId >= g_deviceCnt)) {
        return ihipLogStatus(hipErrorInvalidDevice);
    } else {
        ihipSetTlsDefaultCtx(ihipGetPrimaryCtx(deviceId));
        return ihipLogStatus(hipSuccess);
    }
}

hipError_t hipDeviceSynchronize(void)
{
    HIP_INIT_API();
    return ihipLogStatus(ihipSynchronize());
}

hipError_t hipDeviceReset(void)
{
    HIP_INIT_API();

    auto *ctx = ihipGetTlsDefaultCtx();

    // TODO-HCC
    // This function currently does a user-level cleanup of known resources.
    // It could benefit from KFD support to perform a more "nuclear" clean that would include any associated kernel resources and page table entries.

    if (ctx) {
        // Release ctx resources (streams and memory):
        ctx->locked_reset();
    }

    return ihipLogStatus(hipSuccess);
}

hipError_t ihipDeviceSetState(void)
{
    hipError_t e = hipErrorInvalidContext;
    auto *ctx = ihipGetTlsDefaultCtx();

    if (ctx) {
        ihipDevice_t *deviceHandle = ctx->getWriteableDevice();
        if(deviceHandle->_state == 0)
        {
            deviceHandle->_state = 1;
        }
        e = hipSuccess;
    }

    return ihipLogStatus(e);
}

hipError_t ihipDeviceGetAttribute(int* pi, hipDeviceAttribute_t attr, int device)
{
    hipError_t e = hipSuccess;

    if(pi == nullptr) {
        return ihipLogStatus(hipErrorInvalidValue);
    }

    auto * hipDevice = ihipGetDevice(device);
    hipDeviceProp_t *prop = &hipDevice->_props;
    if (hipDevice) {
        switch (attr) {
        case hipDeviceAttributeMaxThreadsPerBlock:
            *pi = prop->maxThreadsPerBlock; break;
        case hipDeviceAttributeMaxBlockDimX:
            *pi = prop->maxThreadsDim[0]; break;
        case hipDeviceAttributeMaxBlockDimY:
            *pi = prop->maxThreadsDim[1]; break;
        case hipDeviceAttributeMaxBlockDimZ:
            *pi = prop->maxThreadsDim[2]; break;
        case hipDeviceAttributeMaxGridDimX:
            *pi = prop->maxGridSize[0]; break;
        case hipDeviceAttributeMaxGridDimY:
            *pi = prop->maxGridSize[1]; break;
        case hipDeviceAttributeMaxGridDimZ:
            *pi = prop->maxGridSize[2]; break;
        case hipDeviceAttributeMaxSharedMemoryPerBlock:
            *pi = prop->sharedMemPerBlock; break;
        case hipDeviceAttributeTotalConstantMemory:
            *pi = prop->totalConstMem; break;
        case hipDeviceAttributeWarpSize:
            *pi = prop->warpSize; break;
        case hipDeviceAttributeMaxRegistersPerBlock:
            *pi = prop->regsPerBlock; break;
        case hipDeviceAttributeClockRate:
            *pi = prop->clockRate; break;
        case hipDeviceAttributeMemoryClockRate:
            *pi = prop->memoryClockRate; break;
        case hipDeviceAttributeMemoryBusWidth:
            *pi = prop->memoryBusWidth; break;
        case hipDeviceAttributeMultiprocessorCount:
            *pi = prop->multiProcessorCount; break;
        case hipDeviceAttributeComputeMode:
            *pi = prop->computeMode; break;
        case hipDeviceAttributeL2CacheSize:
            *pi = prop->l2CacheSize; break;
        case hipDeviceAttributeMaxThreadsPerMultiProcessor:
            *pi = prop->maxThreadsPerMultiProcessor; break;
        case hipDeviceAttributeComputeCapabilityMajor:
            *pi = prop->major; break;
        case hipDeviceAttributeComputeCapabilityMinor:
            *pi = prop->minor; break;
        case hipDeviceAttributePciBusId:
            *pi = prop->pciBusID; break;
        case hipDeviceAttributeConcurrentKernels:
            *pi = prop->concurrentKernels; break;
        case hipDeviceAttributePciDeviceId:
            *pi = prop->pciDeviceID; break;
        case hipDeviceAttributeMaxSharedMemoryPerMultiprocessor:
            *pi = prop->maxSharedMemoryPerMultiProcessor; break;
        case hipDeviceAttributeIsMultiGpuBoard:
            *pi = prop->isMultiGpuBoard; break;
        default:
            e = hipErrorInvalidValue; break;
        }
    } else {
        e = hipErrorInvalidDevice;
    }
    return ihipLogStatus(e);
}

hipError_t hipDeviceGetAttribute(int* pi, hipDeviceAttribute_t attr, int device)
{
    HIP_INIT_API(pi, attr, device);
    return ihipDeviceGetAttribute(pi,attr,device);
}

hipError_t ihipGetDeviceProperties(hipDeviceProp_t* props, int device)
{
    hipError_t e;

    if(props != nullptr){
        auto * hipDevice = ihipGetDevice(device);
        if (hipDevice) {
        // copy saved props
            *props = hipDevice->_props;
            e = hipSuccess;
        } else {
            e = hipErrorInvalidDevice;
        }
    }else{
        e = hipErrorInvalidDevice;
    }

    return ihipLogStatus(e);
}

hipError_t hipGetDeviceProperties(hipDeviceProp_t* props, int device)
{
    HIP_INIT_API(props, device);
    return ihipGetDeviceProperties(props, device);
}

hipError_t hipSetDeviceFlags( unsigned int flags)
{
    HIP_INIT_API(flags);

    hipError_t e = hipSuccess;

    auto * ctx = ihipGetTlsDefaultCtx();

    // TODO : does this really OR in the flags or replaces previous flags:
    // TODO : Review error handling behavior for this function, it often returns ErrorSetOnActiveProcess
    if (ctx) {
       auto *deviceHandle = ctx->getDevice();
       if(deviceHandle->_state == 0)
       {
           ctx->_ctxFlags = ctx->_ctxFlags | flags;
           if (flags & hipDeviceScheduleMask) {
               switch (hipDeviceScheduleMask) {
                  case hipDeviceScheduleAuto:
                  case hipDeviceScheduleSpin:
                  case hipDeviceScheduleYield:
                  case hipDeviceScheduleBlockingSync:
                       e = hipSuccess;
                       break;
                  default:
                       e = hipSuccess; // TODO - should this be error?  Map to Auto?
                       //e = hipErrorInvalidValue;
                       break;
               }
           }

           unsigned supportedFlags = hipDeviceScheduleMask | hipDeviceMapHost | hipDeviceLmemResizeToMax;

           if (flags & (~supportedFlags)) {
              e = hipErrorInvalidValue;
           }
        } else {
              e = hipErrorSetOnActiveProcess;
        }
        } else {
           e = hipErrorInvalidDevice;
    }

    return ihipLogStatus(e);
};

hipError_t hipDeviceComputeCapability(int *major, int *minor, hipDevice_t device)
{
    HIP_INIT_API(major,minor, device);
    hipError_t e = hipSuccess;
    e = ihipDeviceGetAttribute(major, hipDeviceAttributeComputeCapabilityMajor, device);
    e = ihipDeviceGetAttribute(minor, hipDeviceAttributeComputeCapabilityMinor, device);
    return ihipLogStatus(e);
}

hipError_t hipDeviceGetName(char *name,int len,hipDevice_t device)
{
    HIP_INIT_API(name,len, device);
    hipError_t e = hipSuccess;
    auto deviceHandle = ihipGetDevice(device);
    int nameLen = strlen(deviceHandle->_props.name);
    if(nameLen <= len)
        memcpy(name,deviceHandle->_props.name,nameLen);
    return ihipLogStatus(e);
}

hipError_t hipDeviceGetPCIBusId (char *pciBusId,int len, int device)
{
    HIP_INIT_API(pciBusId, len, device);
    hipError_t e = hipSuccess;
    int tempPciBusId = 0;
    e = ihipDeviceGetAttribute( &tempPciBusId, hipDeviceAttributePciBusId, device);
    if( e == hipSuccess) {
        std::string tempPciStr = std::to_string(tempPciBusId);
        memcpy( pciBusId , tempPciStr.c_str() , tempPciStr.length() );
    }
    return ihipLogStatus(e);
}

hipError_t hipDeviceTotalMem (size_t *bytes,hipDevice_t device)
{
    HIP_INIT_API(bytes, device);
    hipError_t e = hipSuccess;
    auto deviceHandle = ihipGetDevice(device);
    *bytes= deviceHandle->_props.totalGlobalMem;
    return ihipLogStatus(e);
}

hipError_t hipDeviceGetByPCIBusId (int*  device, const int* pciBusId )
{
    HIP_INIT_API(device,pciBusId);
    hipDeviceProp_t  tempProp;
    int deviceCount;
    hipError_t e = hipErrorInvalidValue;
    ihipGetDeviceCount( &deviceCount );
    *device = 0;
    for (int i = 0; i< deviceCount; i++) {
        ihipGetDeviceProperties( &tempProp, i );
        if(tempProp.pciBusID == *pciBusId) {
            *device =i;
            e = hipSuccess;
            break;
        }
    }
    return ihipLogStatus(e);
}

hipError_t hipChooseDevice( int* device, const hipDeviceProp_t* prop )
{
    HIP_INIT_API(device,prop);
    hipDeviceProp_t  tempProp;
    int deviceCount;
    int inPropCount = 0;
    int matchedPropCount = 0;
    hipError_t e = hipSuccess;
    ihipGetDeviceCount( &deviceCount );
    *device = 0;
    for (int i = 0; i < deviceCount; i++) {
        ihipGetDeviceProperties( &tempProp, i );
        if(prop->major != 0) {
            inPropCount++;
            if(tempProp.major >= prop->major) {
                matchedPropCount++;
            }
            if(prop->minor != 0) {
                inPropCount++;
                 if(tempProp.minor >= prop->minor) {
                     matchedPropCount++;
                 }
            }
        }
        if(prop->totalGlobalMem != 0) {
            inPropCount++;
            if(tempProp.totalGlobalMem >= prop->totalGlobalMem) {
                matchedPropCount++;
            }
        }
        if(prop->sharedMemPerBlock != 0) {
            inPropCount++;
            if(tempProp.sharedMemPerBlock >= prop->sharedMemPerBlock) {
                matchedPropCount++;
            }
        }
        if(prop->maxThreadsPerBlock != 0) {
            inPropCount++;
            if(tempProp.maxThreadsPerBlock >= prop->maxThreadsPerBlock ) {
                matchedPropCount++;
            }
        }
        if(prop->totalConstMem != 0) {
            inPropCount++;
            if(tempProp.totalConstMem >= prop->totalConstMem ) {
                matchedPropCount++;
            }
        }
        if(prop->multiProcessorCount != 0) {
            inPropCount++;
            if(tempProp.multiProcessorCount >= prop->multiProcessorCount ) {
                matchedPropCount++;
            }
        }
        if(prop->maxThreadsPerMultiProcessor != 0) {
            inPropCount++;
            if(tempProp.maxThreadsPerMultiProcessor >= prop->maxThreadsPerMultiProcessor ) {
                matchedPropCount++;
            }
        }
        if(prop->memoryClockRate != 0) {
            inPropCount++;
            if(tempProp.memoryClockRate >= prop->memoryClockRate ) {
                matchedPropCount++;
            }
        }
        if(inPropCount == matchedPropCount) {
            *device = i;
        }
#if 0
        else{
            e= hipErrorInvalidValue;
        }
#endif
    }
    return ihipLogStatus(e);
}
<commit_msg>Change ihipDeviceSetState,ihipDevice* so it doesn't log error<commit_after>/*
Copyright (c) 2015-2017 Advanced Micro Devices, Inc. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "hip/hip_runtime.h"
#include "hip_hcc.h"
#include "trace_helper.h"
#include "device_util.h"

//-------------------------------------------------------------------------------------------------
//Devices
//-------------------------------------------------------------------------------------------------
// TODO - does this initialize HIP runtime?
hipError_t hipGetDevice(int *deviceId)
{
    HIP_INIT_API(deviceId);

    hipError_t e = hipSuccess;

    auto ctx = ihipGetTlsDefaultCtx();

    if(deviceId != nullptr){
        if (ctx == nullptr) {
            e = hipErrorInvalidDevice; // TODO, check error code.
            *deviceId = -1;
        } else {
            *deviceId = ctx->getDevice()->_deviceId;
        }
    }else{
        e = hipErrorInvalidValue;
    }

    return ihipLogStatus(e);
}

// TODO - does this initialize HIP runtime?
hipError_t ihipGetDeviceCount(int *count)
{
    hipError_t e = hipSuccess;

    if(count != nullptr) {
        *count = g_deviceCnt;

        if (*count > 0) {
            e = ihipLogStatus(hipSuccess);
        } else {
            e = ihipLogStatus(hipErrorNoDevice);
        }
    } else {
        e = ihipLogStatus(hipErrorInvalidValue);
    }
    return e;
}

hipError_t hipGetDeviceCount(int *count)
{
    HIP_INIT_API(count);
    return ihipGetDeviceCount(count);
}

hipError_t hipDeviceSetCacheConfig(hipFuncCache_t cacheConfig)
{
    HIP_INIT_API(cacheConfig);

    // Nop, AMD does not support variable cache configs.

    return ihipLogStatus(hipSuccess);
}

hipError_t hipDeviceGetCacheConfig(hipFuncCache_t *cacheConfig)
{
    HIP_INIT_API(cacheConfig);

    if(cacheConfig == nullptr) {
        return ihipLogStatus(hipErrorInvalidValue);
    }

    *cacheConfig = hipFuncCachePreferNone;

    return ihipLogStatus(hipSuccess);
}

hipError_t hipDeviceGetLimit (size_t *pValue, hipLimit_t limit)
{
    HIP_INIT_API(pValue, limit);
    if(pValue == nullptr) {
        return ihipLogStatus(hipErrorInvalidValue);
    }
    if(limit == hipLimitMallocHeapSize) {
        *pValue = (size_t)SIZE_OF_HEAP;
        return ihipLogStatus(hipSuccess);
    }else{
        return ihipLogStatus(hipErrorUnsupportedLimit);
    }
}

hipError_t hipFuncSetCacheConfig (hipFuncCache_t cacheConfig)
{
    HIP_INIT_API(cacheConfig);

    // Nop, AMD does not support variable cache configs.

    return ihipLogStatus(hipSuccess);
}

hipError_t hipDeviceSetSharedMemConfig (hipSharedMemConfig config)
{
    HIP_INIT_API(config);

    // Nop, AMD does not support variable shared mem configs.

    return ihipLogStatus(hipSuccess);
}

hipError_t hipDeviceGetSharedMemConfig (hipSharedMemConfig *pConfig)
{
    HIP_INIT_API(pConfig);

    *pConfig = hipSharedMemBankSizeFourByte;

    return ihipLogStatus(hipSuccess);
}

hipError_t hipSetDevice(int deviceId)
{
    HIP_INIT_API(deviceId);
    if ((deviceId < 0) || (deviceId >= g_deviceCnt)) {
        return ihipLogStatus(hipErrorInvalidDevice);
    } else {
        ihipSetTlsDefaultCtx(ihipGetPrimaryCtx(deviceId));
        return ihipLogStatus(hipSuccess);
    }
}

hipError_t hipDeviceSynchronize(void)
{
    HIP_INIT_API();
    return ihipLogStatus(ihipSynchronize());
}

hipError_t hipDeviceReset(void)
{
    HIP_INIT_API();

    auto *ctx = ihipGetTlsDefaultCtx();

    // TODO-HCC
    // This function currently does a user-level cleanup of known resources.
    // It could benefit from KFD support to perform a more "nuclear" clean that would include any associated kernel resources and page table entries.

    if (ctx) {
        // Release ctx resources (streams and memory):
        ctx->locked_reset();
    }

    return ihipLogStatus(hipSuccess);
}

hipError_t ihipDeviceSetState(void)
{
    hipError_t e = hipErrorInvalidContext;
    auto *ctx = ihipGetTlsDefaultCtx();

    if (ctx) {
        ihipDevice_t *deviceHandle = ctx->getWriteableDevice();
        if(deviceHandle->_state == 0)
        {
            deviceHandle->_state = 1;
        }
        e = hipSuccess;
    }

    return e;
}

hipError_t ihipDeviceGetAttribute(int* pi, hipDeviceAttribute_t attr, int device)
{
    hipError_t e = hipSuccess;

    if(pi == nullptr) {
        return ihipLogStatus(hipErrorInvalidValue);
    }

    auto * hipDevice = ihipGetDevice(device);
    hipDeviceProp_t *prop = &hipDevice->_props;
    if (hipDevice) {
        switch (attr) {
        case hipDeviceAttributeMaxThreadsPerBlock:
            *pi = prop->maxThreadsPerBlock; break;
        case hipDeviceAttributeMaxBlockDimX:
            *pi = prop->maxThreadsDim[0]; break;
        case hipDeviceAttributeMaxBlockDimY:
            *pi = prop->maxThreadsDim[1]; break;
        case hipDeviceAttributeMaxBlockDimZ:
            *pi = prop->maxThreadsDim[2]; break;
        case hipDeviceAttributeMaxGridDimX:
            *pi = prop->maxGridSize[0]; break;
        case hipDeviceAttributeMaxGridDimY:
            *pi = prop->maxGridSize[1]; break;
        case hipDeviceAttributeMaxGridDimZ:
            *pi = prop->maxGridSize[2]; break;
        case hipDeviceAttributeMaxSharedMemoryPerBlock:
            *pi = prop->sharedMemPerBlock; break;
        case hipDeviceAttributeTotalConstantMemory:
            *pi = prop->totalConstMem; break;
        case hipDeviceAttributeWarpSize:
            *pi = prop->warpSize; break;
        case hipDeviceAttributeMaxRegistersPerBlock:
            *pi = prop->regsPerBlock; break;
        case hipDeviceAttributeClockRate:
            *pi = prop->clockRate; break;
        case hipDeviceAttributeMemoryClockRate:
            *pi = prop->memoryClockRate; break;
        case hipDeviceAttributeMemoryBusWidth:
            *pi = prop->memoryBusWidth; break;
        case hipDeviceAttributeMultiprocessorCount:
            *pi = prop->multiProcessorCount; break;
        case hipDeviceAttributeComputeMode:
            *pi = prop->computeMode; break;
        case hipDeviceAttributeL2CacheSize:
            *pi = prop->l2CacheSize; break;
        case hipDeviceAttributeMaxThreadsPerMultiProcessor:
            *pi = prop->maxThreadsPerMultiProcessor; break;
        case hipDeviceAttributeComputeCapabilityMajor:
            *pi = prop->major; break;
        case hipDeviceAttributeComputeCapabilityMinor:
            *pi = prop->minor; break;
        case hipDeviceAttributePciBusId:
            *pi = prop->pciBusID; break;
        case hipDeviceAttributeConcurrentKernels:
            *pi = prop->concurrentKernels; break;
        case hipDeviceAttributePciDeviceId:
            *pi = prop->pciDeviceID; break;
        case hipDeviceAttributeMaxSharedMemoryPerMultiprocessor:
            *pi = prop->maxSharedMemoryPerMultiProcessor; break;
        case hipDeviceAttributeIsMultiGpuBoard:
            *pi = prop->isMultiGpuBoard; break;
        default:
            e = hipErrorInvalidValue; break;
        }
    } else {
        e = hipErrorInvalidDevice;
    }
    return e;
}

hipError_t hipDeviceGetAttribute(int* pi, hipDeviceAttribute_t attr, int device)
{
    HIP_INIT_API(pi, attr, device);
    return ihipDeviceGetAttribute(pi,attr,device);
}

hipError_t ihipGetDeviceProperties(hipDeviceProp_t* props, int device)
{
    hipError_t e;

    if(props != nullptr){
        auto * hipDevice = ihipGetDevice(device);
        if (hipDevice) {
        // copy saved props
            *props = hipDevice->_props;
            e = hipSuccess;
        } else {
            e = hipErrorInvalidDevice;
        }
    }else{
        e = hipErrorInvalidDevice;
    }

    return e;
}

hipError_t hipGetDeviceProperties(hipDeviceProp_t* props, int device)
{
    HIP_INIT_API(props, device);
    return ihipGetDeviceProperties(props, device);
}

hipError_t hipSetDeviceFlags( unsigned int flags)
{
    HIP_INIT_API(flags);

    hipError_t e = hipSuccess;

    auto * ctx = ihipGetTlsDefaultCtx();

    // TODO : does this really OR in the flags or replaces previous flags:
    // TODO : Review error handling behavior for this function, it often returns ErrorSetOnActiveProcess
    if (ctx) {
       auto *deviceHandle = ctx->getDevice();
       if(deviceHandle->_state == 0)
       {
           ctx->_ctxFlags = ctx->_ctxFlags | flags;
           if (flags & hipDeviceScheduleMask) {
               switch (hipDeviceScheduleMask) {
                  case hipDeviceScheduleAuto:
                  case hipDeviceScheduleSpin:
                  case hipDeviceScheduleYield:
                  case hipDeviceScheduleBlockingSync:
                       e = hipSuccess;
                       break;
                  default:
                       e = hipSuccess; // TODO - should this be error?  Map to Auto?
                       //e = hipErrorInvalidValue;
                       break;
               }
           }

           unsigned supportedFlags = hipDeviceScheduleMask | hipDeviceMapHost | hipDeviceLmemResizeToMax;

           if (flags & (~supportedFlags)) {
              e = hipErrorInvalidValue;
           }
        } else {
              e = hipErrorSetOnActiveProcess;
        }
        } else {
           e = hipErrorInvalidDevice;
    }

    return ihipLogStatus(e);
};

hipError_t hipDeviceComputeCapability(int *major, int *minor, hipDevice_t device)
{
    HIP_INIT_API(major,minor, device);
    hipError_t e = hipSuccess;
    e = ihipDeviceGetAttribute(major, hipDeviceAttributeComputeCapabilityMajor, device);
    e = ihipDeviceGetAttribute(minor, hipDeviceAttributeComputeCapabilityMinor, device);
    return ihipLogStatus(e);
}

hipError_t hipDeviceGetName(char *name,int len,hipDevice_t device)
{
    HIP_INIT_API(name,len, device);
    hipError_t e = hipSuccess;
    auto deviceHandle = ihipGetDevice(device);
    int nameLen = strlen(deviceHandle->_props.name);
    if(nameLen <= len)
        memcpy(name,deviceHandle->_props.name,nameLen);
    return ihipLogStatus(e);
}

hipError_t hipDeviceGetPCIBusId (char *pciBusId,int len, int device)
{
    HIP_INIT_API(pciBusId, len, device);
    hipError_t e = hipSuccess;
    int tempPciBusId = 0;
    e = ihipDeviceGetAttribute( &tempPciBusId, hipDeviceAttributePciBusId, device);
    if( e == hipSuccess) {
        std::string tempPciStr = std::to_string(tempPciBusId);
        memcpy( pciBusId , tempPciStr.c_str() , tempPciStr.length() );
    }
    return ihipLogStatus(e);
}

hipError_t hipDeviceTotalMem (size_t *bytes,hipDevice_t device)
{
    HIP_INIT_API(bytes, device);
    hipError_t e = hipSuccess;
    auto deviceHandle = ihipGetDevice(device);
    *bytes= deviceHandle->_props.totalGlobalMem;
    return ihipLogStatus(e);
}

hipError_t hipDeviceGetByPCIBusId (int*  device, const int* pciBusId )
{
    HIP_INIT_API(device,pciBusId);
    hipDeviceProp_t  tempProp;
    int deviceCount;
    hipError_t e = hipErrorInvalidValue;
    ihipGetDeviceCount( &deviceCount );
    *device = 0;
    for (int i = 0; i< deviceCount; i++) {
        ihipGetDeviceProperties( &tempProp, i );
        if(tempProp.pciBusID == *pciBusId) {
            *device =i;
            e = hipSuccess;
            break;
        }
    }
    return ihipLogStatus(e);
}

hipError_t hipChooseDevice( int* device, const hipDeviceProp_t* prop )
{
    HIP_INIT_API(device,prop);
    hipDeviceProp_t  tempProp;
    int deviceCount;
    int inPropCount = 0;
    int matchedPropCount = 0;
    hipError_t e = hipSuccess;
    ihipGetDeviceCount( &deviceCount );
    *device = 0;
    for (int i = 0; i < deviceCount; i++) {
        ihipGetDeviceProperties( &tempProp, i );
        if(prop->major != 0) {
            inPropCount++;
            if(tempProp.major >= prop->major) {
                matchedPropCount++;
            }
            if(prop->minor != 0) {
                inPropCount++;
                 if(tempProp.minor >= prop->minor) {
                     matchedPropCount++;
                 }
            }
        }
        if(prop->totalGlobalMem != 0) {
            inPropCount++;
            if(tempProp.totalGlobalMem >= prop->totalGlobalMem) {
                matchedPropCount++;
            }
        }
        if(prop->sharedMemPerBlock != 0) {
            inPropCount++;
            if(tempProp.sharedMemPerBlock >= prop->sharedMemPerBlock) {
                matchedPropCount++;
            }
        }
        if(prop->maxThreadsPerBlock != 0) {
            inPropCount++;
            if(tempProp.maxThreadsPerBlock >= prop->maxThreadsPerBlock ) {
                matchedPropCount++;
            }
        }
        if(prop->totalConstMem != 0) {
            inPropCount++;
            if(tempProp.totalConstMem >= prop->totalConstMem ) {
                matchedPropCount++;
            }
        }
        if(prop->multiProcessorCount != 0) {
            inPropCount++;
            if(tempProp.multiProcessorCount >= prop->multiProcessorCount ) {
                matchedPropCount++;
            }
        }
        if(prop->maxThreadsPerMultiProcessor != 0) {
            inPropCount++;
            if(tempProp.maxThreadsPerMultiProcessor >= prop->maxThreadsPerMultiProcessor ) {
                matchedPropCount++;
            }
        }
        if(prop->memoryClockRate != 0) {
            inPropCount++;
            if(tempProp.memoryClockRate >= prop->memoryClockRate ) {
                matchedPropCount++;
            }
        }
        if(inPropCount == matchedPropCount) {
            *device = i;
        }
#if 0
        else{
            e= hipErrorInvalidValue;
        }
#endif
    }
    return ihipLogStatus(e);
}
<|endoftext|>


<commit_before>/**
 * @file
 * @author  Aapo Kyrola <akyrola@cs.cmu.edu>
 * @version 1.0
 *
 * @section LICENSE
 *
 * Copyright [2012] [Aapo Kyrola, Guy Blelloch, Carlos Guestrin / Carnegie Mellon University]
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.

 *
 * @section DESCRIPTION
 *
 * Graph conversion and parsing routines.
 */

#ifndef GRAPHCHI_CONVERSIONS_DEF
#define GRAPHCHI_CONVERSIONS_DEF

#include <fcntl.h>
#include <unistd.h>

#include <am/graphchi/graphchi_types.hpp>
#include <am/graphchi/logger/logger.hpp>
#include <am/graphchi/preprocessing/sharder.hpp>
#include <am/graphchi/preprocessing/formats/binary_adjacency_list.hpp>

/**
  * GNU COMPILER HACK TO PREVENT WARNINGS "Unused variable", if
  * the particular app being compiled does not use a function.
  */
#ifdef __GNUC__
#define VARIABLE_IS_NOT_USED __attribute__ ((unused))
#else
#define VARIABLE_IS_NOT_USED
#endif

namespace graphchi {

    /* Simple string to number parsers */
    static void VARIABLE_IS_NOT_USED parse(int &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(unsigned int &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(float &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(long &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(char &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(bool &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(double &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(short &x, const char * s);
    static void FIXLINE(char * s);

    static void parse(int &x, const char * s) {
        x = atoi(s);
    }

    static void parse(unsigned int &x, const char * s) {
        x = (unsigned int) strtoul(s, NULL, 10);
    }

    static void parse(float &x, const char * s) {
        x = (float) atof(s);
    }

    /**
     * Special templated parser for PairContainers.
     */
    template <typename T>
    void parse(PairContainer<T> &x, const char * s) {
        parse(x.left, s);
        parse(x.right, s);
    }

    static void parse(long &x, const char * s) {
        x = atol(s);
    }

    static void parse(char &x, const char * s) {
        x = s[0];
    }

    static void parse(bool &x, const char * s) {
        x = atoi(s) == 1;
    }

    static  void parse(double &x, const char * s) {
        x = atof(s);
    }

    static void parse(short &x, const char * s) {
        x = (short) atoi(s);
    }

    // Catch all
    template <typename T>
    void parse(T &x, const char * s) {
        logstream(LOG_FATAL) << "You need to define parse<your-type>(your-type &x, const char *s) function"
        << " to support parsing the edge value." << std::endl;
        assert(false);
    }

    // Removes \n from the end of line
    void FIXLINE(char * s) {
        int len = (int) strlen(s)-1;
        if(s[len] == '\n') s[len] = 0;
    }

    /**
     * Converts graph from an edge list format. Input may contain
     * value for the edges. Self-edges are ignored.
     */
    template <typename EdgeDataType>
    void convert_edgelist(std::string inputfile, sharder<EdgeDataType> &sharderobj) {
        FILE * inf = fopen(inputfile.c_str(), "r");
        size_t bytesread = 0;
        size_t linenum = 0;
        if (inf == NULL) {
            logstream(LOG_FATAL) << "Could not load :" << inputfile << " error: " << strerror(errno) << std::endl;
        }
        assert(inf != NULL);

        logstream(LOG_INFO) << "Reading in edge list format!" << std::endl;
        char s[1024];
        while(fgets(s, 1024, inf) != NULL) {
            linenum++;
            if (linenum % 10000000 == 0) {
                logstream(LOG_DEBUG) << "Read " << linenum << " lines, " << bytesread / 1024 / 1024.  << " MB" << std::endl;
            }
            FIXLINE(s);
            bytesread += strlen(s);
            if (s[0] == '#') continue; // Comment
            if (s[0] == '%') continue; // Comment

            char delims[] = "\t ";
            char * t;
            t = strtok(s, delims);
            vid_t from = atoi(t);
            t = strtok(NULL, delims);
            vid_t to = atoi(t);

            /* Check if has value */
            t = strtok(NULL, delims);
            EdgeDataType val;
            if (t != NULL) {
                parse(val, (const char*) t);
            } else {
                val = EdgeDataType();
            }
            if (from != to) {
                sharderobj.preprocessing_add_edge(from, to, val);
            }
        }
        fclose(inf);
    }

    /**
     * Converts a graph from adjacency list format. Edge values are not supported,
     * and each edge gets the default value for the type. Self-edges are ignored.
     */
    template <typename EdgeDataType>
    void convert_adjlist(std::string inputfile, sharder<EdgeDataType> &sharderobj) {
        FILE * inf = fopen(inputfile.c_str(), "r");
        if (inf == NULL) {
            logstream(LOG_FATAL) << "Could not load :" << inputfile << " error: " << strerror(errno) << std::endl;
        }
        assert(inf != NULL);
        logstream(LOG_INFO) << "Reading in adjacency list format!" << std::endl;

        int maxlen = 100000000;
        char * s = (char*) malloc(maxlen);

        size_t bytesread = 0;

        char delims[] = " \t";
        size_t linenum = 0;
        size_t lastlog = 0;
        /*** PHASE 1 - count ***/
        while(fgets(s, maxlen, inf) != NULL) {
            linenum++;
            if (bytesread - lastlog >= 500000000) {
                logstream(LOG_DEBUG) << "Read " << linenum << " lines, " << bytesread / 1024 / 1024.  << " MB" << std::endl;
                lastlog = bytesread;
            }
            FIXLINE(s);
            bytesread += strlen(s);

            if (s[0] == '#') continue; // Comment
            if (s[0] == '%') continue; // Comment
            char * t = strtok(s, delims);
            vid_t from = atoi(t);
            t = strtok(NULL,delims);
            if (t != NULL) {
                vid_t num = atoi(t);
                vid_t i = 0;
                while((t = strtok(NULL,delims)) != NULL) {
                    vid_t to = atoi(t);
                    if (from != to) {
                        sharderobj.preprocessing_add_edge(from, to, EdgeDataType());
                    }
                    i++;
                }
                if (num != i)
                    logstream(LOG_ERROR) << "Mismatch when reading adjacency list: " << num << " != " << i << " s: " << std::string(s)
                    << " on line: " << linenum << std::endl;
                assert(num == i);
            }
        }
        free(s);
    }

    /**
      * A abstract class for defining preprocessor objects
      * that modify the preprocessed binary input prior
      * to sharding.
      */
    template <typename EdgeDataType>
    class SharderPreprocessor {
    public:
        virtual ~SharderPreprocessor() {}
        virtual std::string getSuffix() = 0;
        virtual void reprocess(std::string preprocFilename, std::string basefileName) = 0;
    };

    /**
      * Converts a graph input to shards. Preprocessing has several steps,
      * see sharder.hpp for more information.
      */
    template <typename EdgeDataType>
    int convert(std::string basefilename, std::string nshards_string, SharderPreprocessor<EdgeDataType> * preprocessor = NULL) {
        std::string suffix = "";
        if (preprocessor != NULL) {
            suffix = preprocessor->getSuffix();
        }
        sharder<EdgeDataType> sharderobj(basefilename + suffix);

        if (!sharderobj.preprocessed_file_exists()) {
            std::string file_type_str = get_option_string("filetype", "edgelist");
            if (file_type_str != "adjlist" && file_type_str != "edgelist") {
                logstream(LOG_ERROR) << "You need to specify filetype: 'edgelist' or 'adjlist'." << std::endl;
                assert(false);
            }

            /* Start preprocessing */
            sharderobj.start_preprocessing();

            if (file_type_str == "adjlist") {
                convert_adjlist<EdgeDataType>(basefilename, sharderobj);
            } else if (file_type_str == "edgelist") {
                convert_edgelist<EdgeDataType>(basefilename, sharderobj);
            }

            /* Finish preprocessing */
            sharderobj.end_preprocessing();

            if (preprocessor != NULL) {
                preprocessor->reprocess(sharderobj.preprocessed_name(), basefilename);
            }

        }

        int nshards = sharderobj.execute_sharding(nshards_string);
        logstream(LOG_INFO) << "Successfully finished sharding for " << basefilename + suffix << std::endl;
        logstream(LOG_INFO) << "Created " << nshards << " shards." << std::endl;
        return nshards;
    }

    template <typename EdgeDataType>
    int convert_if_notexists(std::string basefilename, std::string nshards_string, SharderPreprocessor<EdgeDataType> * preprocessor = NULL) {
        int nshards;
        std::string suffix = "";
        if (preprocessor != NULL) {
            suffix = preprocessor->getSuffix();
        }

        /* Check if input file is already sharded */
        if ((nshards = find_shards<EdgeDataType>(basefilename + suffix, nshards_string))) {
            logstream(LOG_INFO) << "Found preprocessed files for " << basefilename << ", num shards=" << nshards << std::endl;
            return nshards;
        }
        logstream(LOG_INFO) << "Did not find preprocessed shards for " << basefilename + suffix << std::endl;
        logstream(LOG_INFO) << "Will try create them now..." << std::endl;
        nshards = convert<EdgeDataType>(basefilename, nshards_string, preprocessor);
        return nshards;
    }

    /**
     * Special machinery for reordering vertices by
     * their degree, i.e setting their vertex ids to be in the order
     * of vertex degree. This is used at least by the Triangle counting application.
     */

    struct vertex_degree {
        int deg;
        vid_t id;
        vertex_degree() {}
        vertex_degree(int deg, vid_t id) : deg(deg), id(id) {}
    };

    static bool vertex_degree_less(const vertex_degree &a, const vertex_degree &b);
    static bool vertex_degree_less(const vertex_degree &a, const vertex_degree &b) {
        return a.deg < b.deg || (a.deg == b.deg && a.id < b.id);
    }

    /**
      * Special preprocessor which relabels vertices in ascending order
      * of their degree.
      */
    template <typename EdgeDataType>
    class OrderByDegree : public SharderPreprocessor<EdgeDataType> {
        int phase;

    public:
        typedef edge_with_value<EdgeDataType> edge_t;
        vid_t * translate_table;
        vid_t max_vertex_id;
        vertex_degree * degarray;
        binary_adjacency_list_writer<EdgeDataType> * writer;
        OrderByDegree() {
            degarray = NULL;
            writer = NULL;
        }

        ~OrderByDegree() {
            if (degarray != NULL) free(degarray);
            degarray = NULL;
            if (writer != NULL) delete writer;
            writer = NULL;
        }

        std::string getSuffix() {
            return "_degord";
        }

        vid_t translate(vid_t vid) {
            if (vid >= max_vertex_id) return vid;
            return translate_table[vid];
        }

        /**
          * Callback function that binary_adjacency_list_reader
          * invokes. In first phase, the degrees of vertice sare collected.
          * In the next face, they are written out to the degree-ordered data.
          * Note: this version does not preserve edge values!
          */
        void receive_edge(vid_t from, vid_t to, EdgeDataType value) {
            if (phase == 0) {
                degarray[from].deg++;
                degarray[to].deg++;
            } else {
                writer->add_edge(translate(from), translate(to)); // Value is ignored
            }
        }
        void reprocess(std::string preprocessedFile, std::string baseFilename) {

            binary_adjacency_list_reader<EdgeDataType> reader(preprocessedFile);
            max_vertex_id = (vid_t) reader.get_max_vertex_id();

            degarray = (vertex_degree *) calloc(max_vertex_id + 1, sizeof(vertex_degree));
            vid_t nverts = max_vertex_id + 1;
            for(vid_t i=0; i < nverts; i++) {
                degarray[i].id = i;
            }

            phase = 0;
            /* Reader will invoke receive_edge() above */
            reader.read_edges(this);

            /* Now sort */
            quickSort(degarray, nverts, vertex_degree_less);

            /* Create translation table */
            translate_table = (vid_t*) calloc(sizeof(vid_t), nverts);
            for(vid_t i=0; i<nverts; i++) {
                translate_table[degarray[i].id] = i;
            }
            delete degarray;

            /* Write translate table */
            std::string translate_table_file = baseFilename + ".vertexmap";
            int df = open(translate_table_file.c_str(), O_RDWR | O_CREAT, S_IROTH | S_IWOTH | S_IWUSR | S_IRUSR);
            if (df < 0) logstream(LOG_ERROR) << "Could not write vertex map: " << translate_table_file <<
                " error: " << strerror(errno) << std::endl;
            assert(df >= 0);
            pwritea(df, translate_table, nverts, 0);
            close(df);

            /* Now recreate the processed file */
            std::string tmpfilename = preprocessedFile + ".old";
            rename(preprocessedFile.c_str(), tmpfilename.c_str());

            writer = new binary_adjacency_list_writer<EdgeDataType>(preprocessedFile);
            binary_adjacency_list_reader<EdgeDataType> reader2(tmpfilename);

            phase = 1;
            reader2.read_edges(this);

            writer->finish();
            delete writer;
            writer = NULL;

            delete translate_table;
        }

    };

} // end namespace

#endif

<commit_msg>graphchi bugs of handling the largest id vertex in preprocessing<commit_after>/**
 * @file
 * @author  Aapo Kyrola <akyrola@cs.cmu.edu>
 * @version 1.0
 *
 * @section LICENSE
 *
 * Copyright [2012] [Aapo Kyrola, Guy Blelloch, Carlos Guestrin / Carnegie Mellon University]
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.

 *
 * @section DESCRIPTION
 *
 * Graph conversion and parsing routines.
 */

#ifndef GRAPHCHI_CONVERSIONS_DEF
#define GRAPHCHI_CONVERSIONS_DEF

#include <fcntl.h>
#include <unistd.h>

#include <am/graphchi/graphchi_types.hpp>
#include <am/graphchi/logger/logger.hpp>
#include <am/graphchi/preprocessing/sharder.hpp>
#include <am/graphchi/preprocessing/formats/binary_adjacency_list.hpp>

/**
  * GNU COMPILER HACK TO PREVENT WARNINGS "Unused variable", if
  * the particular app being compiled does not use a function.
  */
#ifdef __GNUC__
#define VARIABLE_IS_NOT_USED __attribute__ ((unused))
#else
#define VARIABLE_IS_NOT_USED
#endif

namespace graphchi {

    /* Simple string to number parsers */
    static void VARIABLE_IS_NOT_USED parse(int &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(unsigned int &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(float &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(long &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(char &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(bool &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(double &x, const char * s);
    static void VARIABLE_IS_NOT_USED parse(short &x, const char * s);
    static void FIXLINE(char * s);

    static void parse(int &x, const char * s) {
        x = atoi(s);
    }

    static void parse(unsigned int &x, const char * s) {
        x = (unsigned int) strtoul(s, NULL, 10);
    }

    static void parse(float &x, const char * s) {
        x = (float) atof(s);
    }

    /**
     * Special templated parser for PairContainers.
     */
    template <typename T>
    void parse(PairContainer<T> &x, const char * s) {
        parse(x.left, s);
        parse(x.right, s);
    }

    static void parse(long &x, const char * s) {
        x = atol(s);
    }

    static void parse(char &x, const char * s) {
        x = s[0];
    }

    static void parse(bool &x, const char * s) {
        x = atoi(s) == 1;
    }

    static  void parse(double &x, const char * s) {
        x = atof(s);
    }

    static void parse(short &x, const char * s) {
        x = (short) atoi(s);
    }

    // Catch all
    template <typename T>
    void parse(T &x, const char * s) {
        logstream(LOG_FATAL) << "You need to define parse<your-type>(your-type &x, const char *s) function"
        << " to support parsing the edge value." << std::endl;
        assert(false);
    }

    // Removes \n from the end of line
    void FIXLINE(char * s) {
        int len = (int) strlen(s)-1;
        if(s[len] == '\n') s[len] = 0;
    }

    /**
     * Converts graph from an edge list format. Input may contain
     * value for the edges. Self-edges are ignored.
     */
    template <typename EdgeDataType>
    void convert_edgelist(std::string inputfile, sharder<EdgeDataType> &sharderobj) {
        FILE * inf = fopen(inputfile.c_str(), "r");
        size_t bytesread = 0;
        size_t linenum = 0;
        if (inf == NULL) {
            logstream(LOG_FATAL) << "Could not load :" << inputfile << " error: " << strerror(errno) << std::endl;
        }
        assert(inf != NULL);

        logstream(LOG_INFO) << "Reading in edge list format!" << std::endl;
        char s[1024];
        while(fgets(s, 1024, inf) != NULL) {
            linenum++;
            if (linenum % 10000000 == 0) {
                logstream(LOG_DEBUG) << "Read " << linenum << " lines, " << bytesread / 1024 / 1024.  << " MB" << std::endl;
            }
            FIXLINE(s);
            bytesread += strlen(s);
            if (s[0] == '#') continue; // Comment
            if (s[0] == '%') continue; // Comment

            char delims[] = "\t ";
            char * t;
            t = strtok(s, delims);
            vid_t from = atoi(t);
            t = strtok(NULL, delims);
            vid_t to = atoi(t);

            /* Check if has value */
            t = strtok(NULL, delims);
            EdgeDataType val;
            if (t != NULL) {
                parse(val, (const char*) t);
            } else {
                val = EdgeDataType();
            }
            if (from != to) {
                sharderobj.preprocessing_add_edge(from, to, val);
            }
        }
        fclose(inf);
    }

    /**
     * Converts a graph from adjacency list format. Edge values are not supported,
     * and each edge gets the default value for the type. Self-edges are ignored.
     */
    template <typename EdgeDataType>
    void convert_adjlist(std::string inputfile, sharder<EdgeDataType> &sharderobj) {
        FILE * inf = fopen(inputfile.c_str(), "r");
        if (inf == NULL) {
            logstream(LOG_FATAL) << "Could not load :" << inputfile << " error: " << strerror(errno) << std::endl;
        }
        assert(inf != NULL);
        logstream(LOG_INFO) << "Reading in adjacency list format!" << std::endl;

        int maxlen = 100000000;
        char * s = (char*) malloc(maxlen);

        size_t bytesread = 0;

        char delims[] = " \t";
        size_t linenum = 0;
        size_t lastlog = 0;
        /*** PHASE 1 - count ***/
        while(fgets(s, maxlen, inf) != NULL) {
            linenum++;
            if (bytesread - lastlog >= 500000000) {
                logstream(LOG_DEBUG) << "Read " << linenum << " lines, " << bytesread / 1024 / 1024.  << " MB" << std::endl;
                lastlog = bytesread;
            }
            FIXLINE(s);
            bytesread += strlen(s);

            if (s[0] == '#') continue; // Comment
            if (s[0] == '%') continue; // Comment
            char * t = strtok(s, delims);
            vid_t from = atoi(t);
            t = strtok(NULL,delims);
            if (t != NULL) {
                vid_t num = atoi(t);
                vid_t i = 0;
                while((t = strtok(NULL,delims)) != NULL) {
                    vid_t to = atoi(t);
                    if (from != to) {
                        sharderobj.preprocessing_add_edge(from, to, EdgeDataType());
                    }
                    i++;
                }
                if (num != i)
                    logstream(LOG_ERROR) << "Mismatch when reading adjacency list: " << num << " != " << i << " s: " << std::string(s)
                    << " on line: " << linenum << std::endl;
                assert(num == i);
            }
        }
        free(s);
    }

    /**
      * A abstract class for defining preprocessor objects
      * that modify the preprocessed binary input prior
      * to sharding.
      */
    template <typename EdgeDataType>
    class SharderPreprocessor {
    public:
        virtual ~SharderPreprocessor() {}
        virtual std::string getSuffix() = 0;
        virtual void reprocess(std::string preprocFilename, std::string basefileName) = 0;
    };

    /**
      * Converts a graph input to shards. Preprocessing has several steps,
      * see sharder.hpp for more information.
      */
    template <typename EdgeDataType>
    int convert(std::string basefilename, std::string nshards_string, SharderPreprocessor<EdgeDataType> * preprocessor = NULL) {
        std::string suffix = "";
        if (preprocessor != NULL) {
            suffix = preprocessor->getSuffix();
        }
        sharder<EdgeDataType> sharderobj(basefilename + suffix);

        if (!sharderobj.preprocessed_file_exists()) {
            std::string file_type_str = get_option_string("filetype", "edgelist");
            if (file_type_str != "adjlist" && file_type_str != "edgelist") {
                logstream(LOG_ERROR) << "You need to specify filetype: 'edgelist' or 'adjlist'." << std::endl;
                assert(false);
            }

            /* Start preprocessing */
            sharderobj.start_preprocessing();

            if (file_type_str == "adjlist") {
                convert_adjlist<EdgeDataType>(basefilename, sharderobj);
            } else if (file_type_str == "edgelist") {
                convert_edgelist<EdgeDataType>(basefilename, sharderobj);
            }

            /* Finish preprocessing */
            sharderobj.end_preprocessing();

            if (preprocessor != NULL) {
                preprocessor->reprocess(sharderobj.preprocessed_name(), basefilename);
            }

        }

        int nshards = sharderobj.execute_sharding(nshards_string);
        logstream(LOG_INFO) << "Successfully finished sharding for " << basefilename + suffix << std::endl;
        logstream(LOG_INFO) << "Created " << nshards << " shards." << std::endl;
        return nshards;
    }

    template <typename EdgeDataType>
    int convert_if_notexists(std::string basefilename, std::string nshards_string, SharderPreprocessor<EdgeDataType> * preprocessor = NULL) {
        int nshards;
        std::string suffix = "";
        if (preprocessor != NULL) {
            suffix = preprocessor->getSuffix();
        }

        /* Check if input file is already sharded */
        if ((nshards = find_shards<EdgeDataType>(basefilename + suffix, nshards_string))) {
            logstream(LOG_INFO) << "Found preprocessed files for " << basefilename << ", num shards=" << nshards << std::endl;
            return nshards;
        }
        logstream(LOG_INFO) << "Did not find preprocessed shards for " << basefilename + suffix << std::endl;
        logstream(LOG_INFO) << "Will try create them now..." << std::endl;
        nshards = convert<EdgeDataType>(basefilename, nshards_string, preprocessor);
        return nshards;
    }

    /**
     * Special machinery for reordering vertices by
     * their degree, i.e setting their vertex ids to be in the order
     * of vertex degree. This is used at least by the Triangle counting application.
     */

    struct vertex_degree {
        int deg;
        vid_t id;
        vertex_degree() {}
        vertex_degree(int deg, vid_t id) : deg(deg), id(id) {}
    };

    static bool vertex_degree_less(const vertex_degree &a, const vertex_degree &b);
    static bool vertex_degree_less(const vertex_degree &a, const vertex_degree &b) {
        return a.deg < b.deg || (a.deg == b.deg && a.id < b.id);
    }

    /**
      * Special preprocessor which relabels vertices in ascending order
      * of their degree.
      */
    template <typename EdgeDataType>
    class OrderByDegree : public SharderPreprocessor<EdgeDataType> {
        int phase;

    public:
        typedef edge_with_value<EdgeDataType> edge_t;
        vid_t * translate_table;
        vid_t max_vertex_id;
        vertex_degree * degarray;
        binary_adjacency_list_writer<EdgeDataType> * writer;
        OrderByDegree() {
            degarray = NULL;
            writer = NULL;
        }

        ~OrderByDegree() {
            if (degarray != NULL) free(degarray);
            degarray = NULL;
            if (writer != NULL) delete writer;
            writer = NULL;
        }

        std::string getSuffix() {
            return "_degord";
        }

        vid_t translate(vid_t vid) {
            if (vid > max_vertex_id) return vid;
            return translate_table[vid];
        }

        /**
          * Callback function that binary_adjacency_list_reader
          * invokes. In first phase, the degrees of vertice sare collected.
          * In the next face, they are written out to the degree-ordered data.
          * Note: this version does not preserve edge values!
          */
        void receive_edge(vid_t from, vid_t to, EdgeDataType value) {
            if (phase == 0) {
                degarray[from].deg++;
                degarray[to].deg++;
            } else {
                writer->add_edge(translate(from), translate(to)); // Value is ignored
            }
        }
        void reprocess(std::string preprocessedFile, std::string baseFilename) {

            binary_adjacency_list_reader<EdgeDataType> reader(preprocessedFile);
            max_vertex_id = (vid_t) reader.get_max_vertex_id();

            degarray = (vertex_degree *) calloc(max_vertex_id + 1, sizeof(vertex_degree));
            vid_t nverts = max_vertex_id + 1;
            for(vid_t i=0; i < nverts; i++) {
                degarray[i].id = i;
            }

            phase = 0;
            /* Reader will invoke receive_edge() above */
            reader.read_edges(this);

            /* Now sort */
            quickSort(degarray, nverts, vertex_degree_less);

            /* Create translation table */
            translate_table = (vid_t*) calloc(sizeof(vid_t), nverts);
            for(vid_t i=0; i<nverts; i++) {
                translate_table[degarray[i].id] = i;
            }
            delete degarray;

            /* Write translate table */
            std::string translate_table_file = baseFilename + ".vertexmap";
            int df = open(translate_table_file.c_str(), O_RDWR | O_CREAT, S_IROTH | S_IWOTH | S_IWUSR | S_IRUSR);
            if (df < 0) logstream(LOG_ERROR) << "Could not write vertex map: " << translate_table_file <<
                " error: " << strerror(errno) << std::endl;
            assert(df >= 0);
            pwritea(df, translate_table, nverts * sizeof(vid_t), 0);
            close(df);

            /* Now recreate the processed file */
            std::string tmpfilename = preprocessedFile + ".old";
            rename(preprocessedFile.c_str(), tmpfilename.c_str());

            writer = new binary_adjacency_list_writer<EdgeDataType>(preprocessedFile);
            binary_adjacency_list_reader<EdgeDataType> reader2(tmpfilename);

            phase = 1;
            reader2.read_edges(this);

            writer->finish();
            delete writer;
            writer = NULL;

            delete translate_table;
        }

    };

} // end namespace

#endif

<|endoftext|>


<commit_before>//  (C) Copyright Gennadiy Rozental 2011-2014.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision: 74248 $
//
//  Description : bitwose comparison manipulator implementation
// ***************************************************************************

#ifndef BOOST_TEST_TOOLS_DETAIL_BITWISE_MANIP_HPP_012705GER
#define BOOST_TEST_TOOLS_DETAIL_BITWISE_MANIP_HPP_012705GER

// Boost Test
#include <boost/test/tools/detail/fwd.hpp>
#include <boost/test/tools/detail/indirections.hpp>

#include <boost/test/tools/assertion_result.hpp>
#include <boost/test/tools/assertion.hpp>

// STL
#include <climits>          // for CHAR_BIT

#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

namespace boost {
namespace test_tools {

// ************************************************************************** //
// **************        bitwise comparison manipulator        ************** //
// ************************************************************************** //

struct bitwise {};

//____________________________________________________________________________//

inline int
operator<<( unit_test::lazy_ostream const&, bitwise )   { return 0; }

//____________________________________________________________________________//

namespace tt_detail {

template<typename Lhs, typename Rhs, typename E>
inline assertion_result
bitwise_compare(Lhs const& lhs, Rhs const& rhs, E const& expr )
{
    assertion_result    pr( true );

    std::size_t left_bit_size  = sizeof(Lhs)*CHAR_BIT;
    std::size_t right_bit_size = sizeof(Rhs)*CHAR_BIT;

    static Lhs const leftOne( 1 );
    static Rhs const rightOne( 1 );

    std::size_t total_bits = left_bit_size < right_bit_size ? left_bit_size : right_bit_size;

    for( std::size_t counter = 0; counter < total_bits; ++counter ) {
        if( (lhs & ( leftOne << counter )) != (rhs & (rightOne << counter)) ) {
            if( pr ) {
                pr.message() << " [";
                expr.report( pr.message().stream() );
                pr.message() << "]. Bitwise comparison failed";
                pr = false;
            }
            pr.message() << "\nMismatch at position " << counter;
        }
    }

    if( left_bit_size != right_bit_size ) {
        if( pr ) {
            pr.message() << " [";
            expr.report( pr.message().stream() );
            pr.message() << "]. Bitwise comparison failed";
            pr = false;
        }
        pr.message() << "\nOperands bit sizes mismatch: " << left_bit_size << " != " << right_bit_size;
    }

    return pr;
}

//____________________________________________________________________________//

template<typename T1, typename T2, typename T3, typename T4>
inline assertion_result
operator<<(assertion_evaluate_t<assertion::binary_expr<T1,T2,assertion::op::EQ<T3,T4> > > const& ae, bitwise )
{
    return bitwise_compare( ae.m_e.lhs().value(), ae.m_e.rhs(), ae.m_e );
}

//____________________________________________________________________________//

inline check_type
operator<<( assertion_type const& , bitwise )
{
    return CHECK_BUILT_ASSERTION;
}

//____________________________________________________________________________//

} // namespace tt_detail
} // namespace test_tools
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_TOOLS_DETAIL_BITWISE_MANIP_HPP_012705GER
<commit_msg>some doxygen<commit_after>//  (C) Copyright Gennadiy Rozental 2011-2014.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision: 74248 $
//
//  Description : bitwose comparison manipulator implementation
// ***************************************************************************

#ifndef BOOST_TEST_TOOLS_DETAIL_BITWISE_MANIP_HPP_012705GER
#define BOOST_TEST_TOOLS_DETAIL_BITWISE_MANIP_HPP_012705GER

// Boost Test
#include <boost/test/tools/detail/fwd.hpp>
#include <boost/test/tools/detail/indirections.hpp>

#include <boost/test/tools/assertion_result.hpp>
#include <boost/test/tools/assertion.hpp>

// STL
#include <climits>          // for CHAR_BIT

#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

namespace boost {
namespace test_tools {

// ************************************************************************** //
// **************        bitwise comparison manipulator        ************** //
// ************************************************************************** //

struct bitwise {};

//____________________________________________________________________________//

inline int
operator<<( unit_test::lazy_ostream const&, bitwise )   { return 0; }

//____________________________________________________________________________//

namespace tt_detail {

/*!@brief Precise bit comparison of two operands
 *
 * This class constructs an assertion_result that contains extended information
 * on the bitwise comparison of two operands. In particular the location of the mismatches
 * (if any) are printed in the assertion result.
 */
template<typename Lhs, typename Rhs, typename E>
inline assertion_result
bitwise_compare(Lhs const& lhs, Rhs const& rhs, E const& expr )
{
    assertion_result    pr( true );

    std::size_t left_bit_size  = sizeof(Lhs)*CHAR_BIT;
    std::size_t right_bit_size = sizeof(Rhs)*CHAR_BIT;

    static Lhs const leftOne( 1 );
    static Rhs const rightOne( 1 );

    std::size_t total_bits = left_bit_size < right_bit_size ? left_bit_size : right_bit_size;

    for( std::size_t counter = 0; counter < total_bits; ++counter ) {
        if( (lhs & ( leftOne << counter )) != (rhs & (rightOne << counter)) ) {
            if( pr ) {
                pr.message() << " [";
                expr.report( pr.message().stream() );
                pr.message() << "]. Bitwise comparison failed";
                pr = false;
            }
            pr.message() << "\nMismatch at position " << counter;
        }
    }

    if( left_bit_size != right_bit_size ) {
        if( pr ) {
            pr.message() << " [";
            expr.report( pr.message().stream() );
            pr.message() << "]. Bitwise comparison failed";
            pr = false;
        }
        pr.message() << "\nOperands bit sizes mismatch: " << left_bit_size << " != " << right_bit_size;
    }

    return pr;
}

//____________________________________________________________________________//

template<typename T1, typename T2, typename T3, typename T4>
inline assertion_result
operator<<(assertion_evaluate_t<assertion::binary_expr<T1,T2,assertion::op::EQ<T3,T4> > > const& ae, bitwise )
{
    return bitwise_compare( ae.m_e.lhs().value(), ae.m_e.rhs(), ae.m_e );
}

//____________________________________________________________________________//

inline check_type
operator<<( assertion_type const& , bitwise )
{
    return CHECK_BUILT_ASSERTION;
}

//____________________________________________________________________________//

} // namespace tt_detail
} // namespace test_tools
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_TOOLS_DETAIL_BITWISE_MANIP_HPP_012705GER
<|endoftext|>


<commit_before>/*********************************************************************************
* Copyright (c) 2022 Rob McDonald <ramcdona@calpoly.edu>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Rob McDonald - initial code and implementation
********************************************************************************/

#ifndef eli_geom_intersect_one_d_curve_solver_hpp
#define eli_geom_intersect_one_d_curve_solver_hpp

#include <cmath>
#include <vector>
#include <list>
#include <algorithm>

#include "eli/code_eli.hpp"

#include "eli/mutil/nls/newton_raphson_method.hpp"

#include "eli/geom/curve/piecewise.hpp"

namespace eli
{
  namespace geom
  {
    namespace curve
    {
      template<template<typename, unsigned short, typename> class curve__, typename data__, unsigned short dim__, typename tol__ >
      class piecewise;
    }

    namespace intersect
    {
      namespace internal
      {
        template <typename onedbezcurve__>
        struct onedcurve_g_functor
        {
          const onedbezcurve__ *pc;

          typename onedbezcurve__::data_type operator()(const typename onedbezcurve__::data_type &t) const
          {
            typename onedbezcurve__::data_type tt(t);

            if ( !(tt>=pc->get_t0()) )
            {
              std::cout << "One D Bezier curve g_functor, tt less than minimum.  tt: " << tt << " t0: " << pc->get_t0() << std::endl;
              tt=pc->get_t0();
            }
            if ( !(tt<=pc->get_tmax()) )
            {
              std::cout << "One D Bezier curve g_functor, tt greater than maximum.  tt: " << tt << " tmax: " << pc->get_tmax() << std::endl;
              tt=pc->get_tmax();
            }

            assert((tt>=pc->get_t0()) && (tt<=pc->get_tmax()));

            return pc->f(tt)(0);
          }
        };

        template <typename onedbezcurve__>
        struct onedcurve_gp_functor
        {
          const onedbezcurve__ *pc;

          typename onedbezcurve__::data_type operator()(const typename onedbezcurve__::data_type &t) const
          {
            typename onedbezcurve__::data_type tt(t);

            if ( !(tt>=pc->get_t0()) )
            {
              std::cout << "One D Bezier curve gp_functor, tt less than minimum.  tt: " << tt << " t0: " << pc->get_t0() << std::endl;
              tt=pc->get_t0();
            }
            if ( !(tt<=pc->get_tmax()) )
            {
              std::cout << "One D Bezier curve gp_functor, tt greater than maximum.  tt: " << tt << " tmax: " << pc->get_tmax() << std::endl;
              tt=pc->get_tmax();
            }

            assert((tt>=pc->get_t0()) && (tt<=pc->get_tmax()));

            return pc->fp(tt)(0);
          }
        };
      }

      template<typename onedcurve__>
      typename onedcurve__::data_type find_zero(typename onedcurve__::data_type &t, const onedcurve__ &c, const typename onedcurve__::data_type &t0, const typename onedcurve__::data_type &tmin, const typename onedcurve__::data_type &tmax )
      {
        eli::mutil::nls::newton_raphson_method<typename onedcurve__::data_type> nrm;
        internal::onedcurve_g_functor<onedcurve__> g;
        internal::onedcurve_gp_functor<onedcurve__> gp;
        typename onedcurve__::data_type val0, val;
        typename onedcurve__::tolerance_type tol;

        // setup the functors
        g.pc=&c;
        gp.pc=&c;

        // setup the solver
        nrm.set_absolute_f_tolerance(tol.get_absolute_tolerance());
        nrm.set_max_iteration(10);

        nrm.set_lower_condition( tmin, eli::mutil::nls::iterative_root_base_constrained<typename onedcurve__::data_type>::IRC_EXCLUSIVE);
        nrm.set_upper_condition( tmax, eli::mutil::nls::iterative_root_base_constrained<typename onedcurve__::data_type>::IRC_EXCLUSIVE);

        // set the initial guess
        nrm.set_initial_guess(t0);
        val0 = c.f(t0)(0);

        // find the root
        nrm.find_root(t, g, gp, 0);

        // if root is within bounds and is closer than initial guess
        {
          assert((t>=c.get_t0()) && (t<=c.get_tmax()));

          val = c.f(t)(0);
          if ( std::abs(val) <= std::abs(val0) )
          {
            return val;
          }
        }

        // couldn't find better answer so return initial guess
        t=t0;
        return val0;
      }

      template<typename onedcurve__>
      typename onedcurve__::data_type find_zero(typename onedcurve__::data_type &t, const onedcurve__ &c, const typename onedcurve__::data_type &t0 )
      {
        return find_zero( t, c, t0, c.get_t0(), c.get_tmax() );
      }

      template<typename onedcurve__>
      void findzeros(std::vector< typename onedcurve__::data_type > & optpts,
                     const typename onedcurve__::data_type &tstart,
                     const typename onedcurve__::data_type &tend,
                     const onedcurve__ &objcurve, const typename onedcurve__::index_type &nsplit )
      {
        typedef typename onedcurve__::data_type data_type;

        data_type tmid = ( tstart + tend ) * 0.5;

        onedcurve__ low, high;

        objcurve.split( low, high, 0.5 );

        int nlow = low.numzerocrossings();

        if ( nlow == 0 ) // Curve does not cross zero
        {
        }
        else if ( nlow == -1 ) // Entire curve is zero
        {
          optpts.push_back( ( tstart + tmid ) * 0.5 );
        }
        else  // Curve may have zero crossing
        {
          if ( nsplit <= 0 ) // Reached end of targeted bisection
          { // Check end and mid points, choose closest as candidate start point.
            data_type t = tstart;
            data_type obj = std::abs( low.f( 0 )(0) );
            data_type obj2 = std::abs( low.f( 0.5 )(0) );
            if ( obj2 < obj )
            {
              obj = obj2;
              t = ( tstart + tmid ) * 0.5;
            }
            obj2 = std::abs( low.f( 1 )(0) );
            if ( obj2 < obj )
            {
              t = tmid;
            }
            optpts.push_back( t );
          }
          else // Recurse to next level
          {
            findzeros( optpts, tstart, tmid, low, nsplit - 1 );
          }
        }

        int nhigh = high.numzerocrossings();

        if ( nhigh == 0 ) // Curve does not cross zero
        {
        }
        else if ( nhigh == -1 ) // Entire curve is zero
        {
          optpts.push_back( ( tmid + tend ) * 0.5 );
        }
        else  // Curve may have zero crossing
        {
          if ( nsplit <= 0 ) // Reached end of targeted bisection
          { // Check end and mid points, choose closest as candidate start point.
            data_type t = tmid;
            data_type obj = std::abs( high.f( 0 )(0) );
            data_type obj2 = std::abs( high.f( 0.5 )(0) );
            if ( obj2 < obj )
            {
              obj = obj2;
              t = ( tmid + tend ) * 0.5;
            }
            obj2 = std::abs( high.f( 1 )(0) );
            if ( obj2 < obj )
            {
              t = tend;
            }
            optpts.push_back( t );
          }
          else // Recurse to next level
          {
            findzeros( optpts, tmid, tend, high, nsplit - 1 );
          }
        }
      }

    }
  }
}
#endif
<commit_msg>Capture and handle non-convergence in one_d_curve_solver<commit_after>/*********************************************************************************
* Copyright (c) 2022 Rob McDonald <ramcdona@calpoly.edu>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Rob McDonald - initial code and implementation
********************************************************************************/

#ifndef eli_geom_intersect_one_d_curve_solver_hpp
#define eli_geom_intersect_one_d_curve_solver_hpp

#include <cmath>
#include <vector>
#include <list>
#include <algorithm>

#include "eli/code_eli.hpp"

#include "eli/mutil/nls/newton_raphson_method.hpp"

#include "eli/geom/curve/piecewise.hpp"

namespace eli
{
  namespace geom
  {
    namespace curve
    {
      template<template<typename, unsigned short, typename> class curve__, typename data__, unsigned short dim__, typename tol__ >
      class piecewise;
    }

    namespace intersect
    {
      namespace internal
      {
        template <typename onedbezcurve__>
        struct onedcurve_g_functor
        {
          const onedbezcurve__ *pc;

          typename onedbezcurve__::data_type operator()(const typename onedbezcurve__::data_type &t) const
          {
            typename onedbezcurve__::data_type tt(t);

            if ( !(tt>=pc->get_t0()) )
            {
              std::cout << "One D Bezier curve g_functor, tt less than minimum.  tt: " << tt << " t0: " << pc->get_t0() << std::endl;
              tt=pc->get_t0();
            }
            if ( !(tt<=pc->get_tmax()) )
            {
              std::cout << "One D Bezier curve g_functor, tt greater than maximum.  tt: " << tt << " tmax: " << pc->get_tmax() << std::endl;
              tt=pc->get_tmax();
            }

            assert((tt>=pc->get_t0()) && (tt<=pc->get_tmax()));

            return pc->f(tt)(0);
          }
        };

        template <typename onedbezcurve__>
        struct onedcurve_gp_functor
        {
          const onedbezcurve__ *pc;

          typename onedbezcurve__::data_type operator()(const typename onedbezcurve__::data_type &t) const
          {
            typename onedbezcurve__::data_type tt(t);

            if ( !(tt>=pc->get_t0()) )
            {
              std::cout << "One D Bezier curve gp_functor, tt less than minimum.  tt: " << tt << " t0: " << pc->get_t0() << std::endl;
              tt=pc->get_t0();
            }
            if ( !(tt<=pc->get_tmax()) )
            {
              std::cout << "One D Bezier curve gp_functor, tt greater than maximum.  tt: " << tt << " tmax: " << pc->get_tmax() << std::endl;
              tt=pc->get_tmax();
            }

            assert((tt>=pc->get_t0()) && (tt<=pc->get_tmax()));

            return pc->fp(tt)(0);
          }
        };
      }

      template<typename onedcurve__>
      typename onedcurve__::data_type find_zero(typename onedcurve__::data_type &t, const onedcurve__ &c, const typename onedcurve__::data_type &t0, const typename onedcurve__::data_type &tmin, const typename onedcurve__::data_type &tmax )
      {
        eli::mutil::nls::newton_raphson_method<typename onedcurve__::data_type> nrm;
        internal::onedcurve_g_functor<onedcurve__> g;
        internal::onedcurve_gp_functor<onedcurve__> gp;
        typename onedcurve__::data_type val0, val;
        typename onedcurve__::tolerance_type tol;

        // setup the functors
        g.pc=&c;
        gp.pc=&c;

        // setup the solver
        nrm.set_absolute_f_tolerance(tol.get_absolute_tolerance());
        nrm.set_max_iteration(10);

        nrm.set_lower_condition( tmin, eli::mutil::nls::iterative_root_base_constrained<typename onedcurve__::data_type>::IRC_EXCLUSIVE);
        nrm.set_upper_condition( tmax, eli::mutil::nls::iterative_root_base_constrained<typename onedcurve__::data_type>::IRC_EXCLUSIVE);

        // set the initial guess
        nrm.set_initial_guess(t0);
        val0 = c.f(t0)(0);

        // find the root
        int ret = nrm.find_root(t, g, gp, 0);

        if ( (ret == nrm.converged) && (t>=tmin) && (t<=tmax))
        {
          val = c.f(t)(0);
          if ( std::abs(val) <= std::abs(val0) )
          {
            return val;
          }
        }

        // couldn't find better answer so return initial guess
        t=t0;
        return val0;
      }

      template<typename onedcurve__>
      typename onedcurve__::data_type find_zero(typename onedcurve__::data_type &t, const onedcurve__ &c, const typename onedcurve__::data_type &t0 )
      {
        return find_zero( t, c, t0, c.get_t0(), c.get_tmax() );
      }

      template<typename onedcurve__>
      void findzeros(std::vector< typename onedcurve__::data_type > & optpts,
                     const typename onedcurve__::data_type &tstart,
                     const typename onedcurve__::data_type &tend,
                     const onedcurve__ &objcurve, const typename onedcurve__::index_type &nsplit )
      {
        typedef typename onedcurve__::data_type data_type;

        data_type tmid = ( tstart + tend ) * 0.5;

        onedcurve__ low, high;

        objcurve.split( low, high, 0.5 );

        int nlow = low.numzerocrossings();

        if ( nlow == 0 ) // Curve does not cross zero
        {
        }
        else if ( nlow == -1 ) // Entire curve is zero
        {
          optpts.push_back( ( tstart + tmid ) * 0.5 );
        }
        else  // Curve may have zero crossing
        {
          if ( nsplit <= 0 ) // Reached end of targeted bisection
          { // Check end and mid points, choose closest as candidate start point.
            data_type t = tstart;
            data_type obj = std::abs( low.f( 0 )(0) );
            data_type obj2 = std::abs( low.f( 0.5 )(0) );
            if ( obj2 < obj )
            {
              obj = obj2;
              t = ( tstart + tmid ) * 0.5;
            }
            obj2 = std::abs( low.f( 1 )(0) );
            if ( obj2 < obj )
            {
              t = tmid;
            }
            optpts.push_back( t );
          }
          else // Recurse to next level
          {
            findzeros( optpts, tstart, tmid, low, nsplit - 1 );
          }
        }

        int nhigh = high.numzerocrossings();

        if ( nhigh == 0 ) // Curve does not cross zero
        {
        }
        else if ( nhigh == -1 ) // Entire curve is zero
        {
          optpts.push_back( ( tmid + tend ) * 0.5 );
        }
        else  // Curve may have zero crossing
        {
          if ( nsplit <= 0 ) // Reached end of targeted bisection
          { // Check end and mid points, choose closest as candidate start point.
            data_type t = tmid;
            data_type obj = std::abs( high.f( 0 )(0) );
            data_type obj2 = std::abs( high.f( 0.5 )(0) );
            if ( obj2 < obj )
            {
              obj = obj2;
              t = ( tmid + tend ) * 0.5;
            }
            obj2 = std::abs( high.f( 1 )(0) );
            if ( obj2 < obj )
            {
              t = tend;
            }
            optpts.push_back( t );
          }
          else // Recurse to next level
          {
            findzeros( optpts, tmid, tend, high, nsplit - 1 );
          }
        }
      }

    }
  }
}
#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2017 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/wkt/wkt_generator_grammar.hpp>
#include <mapnik/geometry/fusion_adapted.hpp>

namespace mapnik { namespace wkt {

template <typename OutputIterator, typename Geometry>
wkt_generator_grammar<OutputIterator, Geometry>::wkt_generator_grammar()
    : wkt_generator_grammar::base_type(geometry)
{
    boost::spirit::karma::lit_type lit;
    geometry =
        point
        |
        linestring
        |
        polygon
        |
        multi_point
        |
        multi_linestring
        |
        multi_polygon
        |
        geometry_collection
        |
        lit("POINT EMPTY") // special case for geometry_empty
        ;

    point = lit("POINT(") << point_coord << lit(")")
        ;

    linestring = lit("LINESTRING") << (linestring_coord | lit(" EMPTY"))
        ;

    polygon = lit("POLYGON") << (polygon_coord | lit(" EMPTY"))
        ;

    multi_point = lit("MULTIPOINT") << (multi_point_coord | lit(" EMPTY"))
        ;

    multi_linestring = lit("MULTILINESTRING") << (multi_linestring_coord | lit(" EMPTY"))
        ;

    multi_polygon = lit("MULTIPOLYGON") << (multi_polygon_coord | lit(" EMPTY"))
        ;

    geometry_collection = lit("GEOMETRYCOLLECTION") << (lit("(") << geometries  << lit(")") | lit(" EMPTY"))
        ;

    point_coord = coordinate << lit(' ') << coordinate
        ;

    linestring_coord = lit('(') << point_coord % lit(',') << lit(')')
        ;

    linear_ring_coord = lit('(') << point_coord % lit(',') << lit(')');//linestring_coord.alias()
        ;

    polygon_coord = linear_ring_coord % lit(',')
        ;

    multi_point_coord = lit('(') << point_coord % lit(',') << lit(')');//linestring_coord.alias()
        ;

    multi_linestring_coord = lit("(") << linestring_coord % lit(',') << lit(")")
        ;

    multi_polygon_coord = lit("(") << polygon_coord % lit(',') << lit(")")
        ;

    geometries = geometry % lit(',')
        ;

}

}}
<commit_msg>fix `polygon_coord` rule to generate required enclosing brackets.<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2017 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/wkt/wkt_generator_grammar.hpp>
#include <mapnik/geometry/fusion_adapted.hpp>

namespace mapnik { namespace wkt {

template <typename OutputIterator, typename Geometry>
wkt_generator_grammar<OutputIterator, Geometry>::wkt_generator_grammar()
    : wkt_generator_grammar::base_type(geometry)
{
    boost::spirit::karma::lit_type lit;
    geometry =
        point
        |
        linestring
        |
        polygon
        |
        multi_point
        |
        multi_linestring
        |
        multi_polygon
        |
        geometry_collection
        |
        lit("POINT EMPTY") // special case for geometry_empty
        ;

    point = lit("POINT(") << point_coord << lit(")")
        ;

    linestring = lit("LINESTRING") << (linestring_coord | lit(" EMPTY"))
        ;

    polygon = lit("POLYGON") << (polygon_coord | lit(" EMPTY"))
        ;

    multi_point = lit("MULTIPOINT") << (multi_point_coord | lit(" EMPTY"))
        ;

    multi_linestring = lit("MULTILINESTRING") << (multi_linestring_coord | lit(" EMPTY"))
        ;

    multi_polygon = lit("MULTIPOLYGON") << (multi_polygon_coord | lit(" EMPTY"))
        ;

    geometry_collection = lit("GEOMETRYCOLLECTION") << (lit("(") << geometries  << lit(")") | lit(" EMPTY"))
        ;

    point_coord = coordinate << lit(' ') << coordinate
        ;

    linestring_coord = lit('(') << point_coord % lit(',') << lit(')')
        ;

    linear_ring_coord = lit('(') << point_coord % lit(',') << lit(')');//linestring_coord.alias()

    polygon_coord = lit('(') << linear_ring_coord % lit(',') << lit(')');
        ;

    multi_point_coord = lit('(') << point_coord % lit(',') << lit(')') //linestring_coord.alias()
        ;

    multi_linestring_coord = lit("(") << linestring_coord % lit(',') << lit(")")
        ;

    multi_polygon_coord = lit("(") << polygon_coord % lit(',') << lit(")")
        ;

    geometries = geometry % lit(',')
        ;

}

}}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: image_util.cpp 36 2005-04-05 14:32:18Z pavlenko $

// stl
#include <string>
// mapnik
#include <mapnik/graphics.hpp>
#include <mapnik/memory.hpp>
#include <mapnik/image_util.hpp>
// jpeg png
extern "C"
{
#include <png.h>
#include <jpeglib.h>
}

namespace mapnik
{

    //use memory manager for mem allocation in libpng

    png_voidp malloc_fn(png_structp png_ptr,png_size_t size)
    {
        return Object::operator new(size);
    }
    void free_fn(png_structp png_ptr, png_voidp ptr)
    {
        Object::operator delete(ptr);
    }
    //
    void ImageUtils::save_to_file(const std::string& filename,
                                  const std::string& type,
                                  const Image32& image)
    {
        //all that should go into image_writer factory
        if (type=="png")
        {
            save_as_png(filename,image);
        }
        else if (type=="jpeg")
        {
            save_as_jpeg(filename,85,image);
        }
    }

    void ImageUtils::save_as_png(const std::string& filename,const Image32& image)
    {
        FILE *fp=fopen(filename.c_str(), "wb");
        if (!fp) return;
        png_voidp mem_ptr=0;
        png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                                    (png_voidp)mem_ptr,0, 0);

        if (!png_ptr) return;
        png_set_mem_fn(png_ptr,mem_ptr,malloc_fn,free_fn);

        // switch on optimization
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
        png_uint_32 mask, flags;

        flags = png_get_asm_flags(png_ptr);
        mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
        png_set_asm_flags(png_ptr, flags | mask);
#endif
        png_set_filter (png_ptr, 0, PNG_FILTER_NONE);
        png_infop info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
        {
            png_destroy_write_struct(&png_ptr,(png_infopp)0);
            fclose(fp);
            return;
        }
        if (setjmp(png_jmpbuf(png_ptr)))
        {
            png_destroy_write_struct(&png_ptr, &info_ptr);
            fclose(fp);
            return;
        }

        png_init_io(png_ptr, fp);
        //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
        //png_set_compression_strategy(png_ptr, Z_FILTERED);
        png_set_IHDR(png_ptr, info_ptr,image.width(),image.height(),8,
                     PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
        png_write_info(png_ptr, info_ptr);

        const ImageData32& imageData=image.data();

        for (unsigned i=0;i<image.height();i++)
        {
            png_write_row(png_ptr,(png_bytep)imageData.getRow(i));
        }

        png_write_end(png_ptr, info_ptr);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        fclose(fp);
    }

    void ImageUtils::save_as_jpeg(const std::string& filename,int quality, const Image32& image)
    {
        FILE *fp=fopen(filename.c_str(), "wb");
        if (!fp) return;
        struct jpeg_compress_struct cinfo;
        struct jpeg_error_mgr jerr;

        int width=image.width();
        int height=image.height();

        cinfo.err = jpeg_std_error(&jerr);
        jpeg_create_compress(&cinfo);
        jpeg_stdio_dest(&cinfo, fp);
        cinfo.image_width = width;
        cinfo.image_height = height;
        cinfo.input_components = 3;
        cinfo.in_color_space = JCS_RGB;
        jpeg_set_defaults(&cinfo);
        jpeg_set_quality(&cinfo, quality,1);
        jpeg_start_compress(&cinfo, 1);
        JSAMPROW row_pointer[1];
        JSAMPLE* row=new JSAMPLE[width*3];
        const ImageData32& imageData=image.data();
        while (cinfo.next_scanline < cinfo.image_height)
        {
            const unsigned* imageRow=imageData.getRow(cinfo.next_scanline);
            int index=0;
            for (int i=0;i<width;++i)
            {
                row[index++]=(imageRow[i])&0xff;
                row[index++]=(imageRow[i]>>8)&0xff;
                row[index++]=(imageRow[i]>>16)&0xff;
            }
            row_pointer[0] = &row[0];
            (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
        }
        delete [] row;
        jpeg_finish_compress(&cinfo);
        fclose(fp);
        jpeg_destroy_compress(&cinfo);
    }
}
<commit_msg>added extra check to compile on x86_64 Gentoo.<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: image_util.cpp 36 2005-04-05 14:32:18Z pavlenko $

// stl
#include <string>
// mapnik
#include <mapnik/graphics.hpp>
#include <mapnik/memory.hpp>
#include <mapnik/image_util.hpp>
// jpeg png
extern "C"
{
#include <png.h>
#include <jpeglib.h>
}

namespace mapnik
{

    //use memory manager for mem allocation in libpng

    png_voidp malloc_fn(png_structp png_ptr,png_size_t size)
    {
        return Object::operator new(size);
    }
    void free_fn(png_structp png_ptr, png_voidp ptr)
    {
        Object::operator delete(ptr);
    }
    //
    void ImageUtils::save_to_file(const std::string& filename,
                                  const std::string& type,
                                  const Image32& image)
    {
        //all that should go into image_writer factory
        if (type=="png")
        {
            save_as_png(filename,image);
        }
        else if (type=="jpeg")
        {
            save_as_jpeg(filename,85,image);
        }
    }

    void ImageUtils::save_as_png(const std::string& filename,const Image32& image)
    {
        FILE *fp=fopen(filename.c_str(), "wb");
        if (!fp) return;
        png_voidp mem_ptr=0;
        png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                                    (png_voidp)mem_ptr,0, 0);

        if (!png_ptr) return;
        png_set_mem_fn(png_ptr,mem_ptr,malloc_fn,free_fn);

        // switch on optimization only if supported
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_ASSEMBLER_CODE_SUPPORTED)
        png_uint_32 mask, flags;

        flags = png_get_asm_flags(png_ptr);
        mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
        png_set_asm_flags(png_ptr, flags | mask);
#endif
        png_set_filter (png_ptr, 0, PNG_FILTER_NONE);
        png_infop info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
        {
            png_destroy_write_struct(&png_ptr,(png_infopp)0);
            fclose(fp);
            return;
        }
        if (setjmp(png_jmpbuf(png_ptr)))
        {
            png_destroy_write_struct(&png_ptr, &info_ptr);
            fclose(fp);
            return;
        }

        png_init_io(png_ptr, fp);
        //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
        //png_set_compression_strategy(png_ptr, Z_FILTERED);
        png_set_IHDR(png_ptr, info_ptr,image.width(),image.height(),8,
                     PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
        png_write_info(png_ptr, info_ptr);

        const ImageData32& imageData=image.data();

        for (unsigned i=0;i<image.height();i++)
        {
            png_write_row(png_ptr,(png_bytep)imageData.getRow(i));
        }

        png_write_end(png_ptr, info_ptr);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        fclose(fp);
    }

    void ImageUtils::save_as_jpeg(const std::string& filename,int quality, const Image32& image)
    {
        FILE *fp=fopen(filename.c_str(), "wb");
        if (!fp) return;
        struct jpeg_compress_struct cinfo;
        struct jpeg_error_mgr jerr;

        int width=image.width();
        int height=image.height();

        cinfo.err = jpeg_std_error(&jerr);
        jpeg_create_compress(&cinfo);
        jpeg_stdio_dest(&cinfo, fp);
        cinfo.image_width = width;
        cinfo.image_height = height;
        cinfo.input_components = 3;
        cinfo.in_color_space = JCS_RGB;
        jpeg_set_defaults(&cinfo);
        jpeg_set_quality(&cinfo, quality,1);
        jpeg_start_compress(&cinfo, 1);
        JSAMPROW row_pointer[1];
        JSAMPLE* row=new JSAMPLE[width*3];
        const ImageData32& imageData=image.data();
        while (cinfo.next_scanline < cinfo.image_height)
        {
            const unsigned* imageRow=imageData.getRow(cinfo.next_scanline);
            int index=0;
            for (int i=0;i<width;++i)
            {
                row[index++]=(imageRow[i])&0xff;
                row[index++]=(imageRow[i]>>8)&0xff;
                row[index++]=(imageRow[i]>>16)&0xff;
            }
            row_pointer[0] = &row[0];
            (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
        }
        delete [] row;
        jpeg_finish_compress(&cinfo);
        fclose(fp);
        jpeg_destroy_compress(&cinfo);
    }
}
<|endoftext|>