U
    dh                     @   sp  d Z ddlmZ ddlmZmZmZmZmZ ddl	Z	ddl
Z
ddlZddlZddlZddlmZ ddlZddlZddlZddlZdd Zdd Zd	d
 Zdd Zdd Zejdedejjgdddejjdd ejdeejjgdddejjdd ejdeejjgdddejjdd ej e r4dn
e!dd dKddZ"ej#dfdd Z$ej#dd!fd"d#Z%dd$ej#dd!fd%d&Z&dd'ej#dfd(d)Z'd*d+ Z(dLd,d-Z)dd$ej#dde(d!fd.d/Z*dMd0d1Z+dd$ej#ddd!e(ej,fd2d3Z-d4d5 Z.dd$ej#dfd6d7Z/dd'ej#dfd8d9Z0e1 Z2ej1ej3d:Z4ej1ej5d:Z6ej1ej7d:Z8ej9r\e4gng Z:ej;rne6gng Z<ej=re8gng Z>e2ge: Z?e?e< Z@e2gd;d< eAeB D  ZCd=d> ZDd?d@ ZEeFeE eD dAZGeFeHe2geIe2gdAZJeFeHe:eIe:dAZKeFeHe>eIe>dAZLeFeHe?eIe?dAZMe	jNdNdCdDZOdOdEdFZPdPdGdHZQG dIdJ dJejRZSdS )Qaq  
The Hypothesis library uses *property-based testing* to check
invariants about the code under test under a variety of random inputs.

 The key idea here is to express properties of the code under test
(e.g. that it passes a gradient check, that it implements a reference
function, etc), and then generate random instances and verify they
satisfy these properties.

The main functions of interest are exposed on `HypothesisTestCase`.
You can usually just add a short function in this to generate an
arbitrary number of test cases for your operator.

The key functions are:

- `assertDeviceChecks(devices, op, inputs, outputs)`. This asserts that the
  operator computes the same outputs, regardless of which device it is executed
  on.
- `assertGradientChecks(device, op, inputs, output_,
  outputs_with_grads)`. This implements a standard numerical gradient checker
  for the operator in question.
- `assertReferenceChecks(device, op, inputs, reference)`. This runs the
  reference function (effectively calling `reference(*inputs)`, and comparing
  that to the output of output.

`hypothesis_test_util.py` exposes some useful pre-built samplers.

- `hu.gcs` - a gradient checker device (`gc`) and device checker devices (`dc`)

- `hu.gcs_cpu_only` - a CPU-only gradient checker device (`gc`) and
  device checker devices (`dc`). Used for when your operator is only
  implemented on the CPU.
    )
caffe2_pb2)	workspacedevice_checkergradient_checker	test_utilcoreNc                   C   s   t ddkpt ddkS )NZ
SANDCASTLE1ZTW_JOB_USER
sandcastle)osgetenv r   r   F/tmp/pip-unpacked-wheel-ua33x9lu/caffe2/python/hypothesis_test_util.pyis_sandcastle8   s    r   c                   C   s
   dt jkS )NZTRAVIS)r
   environr   r   r   r   	is_travis<   s    r   c                 C   s   t dt dt| d S )Nfr   )structunpackpackfloatxr   r   r   
to_float32@   s    r   c                  O   s~   d|krt jjdkr|d d|kr<t jjdk r<|d d|krrt jjdkrrd|krh|d d |d< |d t j| |S )Nmin_satisfying_examples)   8   r   deadline)   ,   r   timeoutg     @@)
hypothesisversion__version_info__popsettings)argskwargsr   r   r   r$   F   s    


r$   c                  O   s   t jjdk}d|kr"|s"|d d|krv|rvd|d< |dd d k	rVt|d |d< |dd d k	rvt|d |d< tj| |S )N)r   C   r   width    	min_value	max_value)r    r!   r"   r#   getr   stfloats)r%   r&   Zwidth_supportedr   r   r   r.   V   s    
r.   r	   T2      i'  )Zderandomizesuppress_health_checkdatabasemax_examplesr   	verbosityr   dev
   )r1   r2   r3   r   r4   r   debugi  iP  ZCAFFE2_HYPOTHESIS_PROFILE   c                 C   s   t j| |dS )Nr*   r+   )r-   integersr9   r   r   r   dims   s    r;   c                 C   s   d }| t jkrtdddd}n| t jkr8tdddd}nj| t jkrRtdddd}nP| t jkrltjddd	}n6| t jkrtjdd
d	}n| t j	krt
 }ntd|d kr|S ||S )Ng      g      ?   )r*   r+   r(   r)   @   r   ir9   l    z*Unexpected dtype without elements provided)npZfloat16r.   float32float64int32r-   r:   int64boolbooleans
ValueErrorfilter)dtypeZfilter_elemsr   r   r   elements_of_type   s    






rI   Fc                 C   s&   |d krt |}tjjj|| ||dS )N)elementsunique)rI   r    extranumpyarrays)r;   rG   rJ   rK   r   r   r   rN      s    rN   r   c                    s,   t jtf || |d}| fddS )NZmin_sizemax_sizec                    s   t |  dS )N)rK   )rN   r;   rG   rJ   rK   r   r   <lambda>       ztensor.<locals>.<lambda>r-   listsr;   flatmap)min_dimmax_dimrG   rJ   rK   r&   dims_r   rR   r   tensor   s    r[   r=   c                 C   s   t dd||| |dS Nr0   r9   )r[   )min_lenmax_lenrG   rJ   r   r   r   tensor1d   s    r_   c                 C   sh   | dkr t tjdgtjdS |rDt| gtjt  ddd S t| gtjt jdd|  ddS d S )Nr   shaperG   rG   rJ   c                 S   s   t j| t jd| d  S )NrG   r   )r>   ZcumsumrA   r   r   r   r   rS      rT   zsegment_ids.<locals>.<lambda>   r9   )	r-   justr>   emptyrA   rN   rD   mapr:   )size	is_sortedr   r   r   segment_ids   s    rj   c                    s   |d krd}|d kr }|dks$t ||ks0t  dkrX|dkrXttjdgtjdS |dksht dtjt|d d|d d fdd	 fdd	t
	tjS )	Nr   r`   z(size is not 0, need at least one segmentr0   r9   c                    s    t jjjtj| tjd ddS )Nr   r9   )rJ   )r    rL   rM   rN   r>   rA   r-   r:   )Znum_bordersrh   r   r   rS      s       zlengths.<locals>.<lambda>c                    s   t | t jd gt jdS )Nr   rc   )r>   appendarrayrA   r   rk   r   r   rS      rT   )AssertionErrorr-   re   r>   rf   rA   r:   maxrW   rg   sortedZdiff)rh   min_segmentsmax_segmentsr&   r   rk   r   lengths   s*     


rs   c           
         sZ   |rt  nt d}t jtf || |d}	t ||	dd }	|	 fddS )NFrO   c                 S   s   | d rdgng | d  S )Nr   r0   r   pairr   r   r   rS      rT   z"segmented_tensor.<locals>.<lambda>c                    s    t t|  | d dS )Nr   ri   )r-   tuplesrN   )Z	data_dimsrG   rJ   ri   segment_generatorr   r   rS      s   
)r-   rD   re   rV   r;   rw   rg   rW   )
rX   rY   rG   ri   rJ   ry   allow_emptyr&   	gen_empty
data_dims_r   rx   r   segmented_tensor   s    
 r}   c                 O   s"   t jt| |d}t|d|i|S )N)rq   rr   ry   )	functoolspartialrs   r}   )rq   rr   r%   r&   genr   r   r   lengths_tensor   s      r   c                    s\   |rt  nt d}	t jtf || |d}
t |	|
dd }| fddS )NFrO   c                 S   s:   t t | d | d s.t jd| d d dnt dS )Nr0   r   r9   )r-   rw   re   r:   rt   r   r   r   rS     s   z)sparse_segmented_tensor.<locals>.<lambda>c              
      sJ   t t| d  t| d t jd| d d d dd| d dS )Nr   r0   r9   rb   rv   )r-   rw   rN   r:   rQ   rG   rJ   ri   itypery   r   r   rS     s    )r-   rD   re   rV   r;   rw   rW   )rX   rY   rG   ri   rJ   rz   ry   r   r&   r{   r|   Z	all_dims_r   r   r   sparse_segmented_tensor  s    r   c                  K   s   t f dti| S )Nry   )r   rs   )r&   r   r   r   sparse_lengths_tensor  s    r   c                    s,   t jtf |||d}| fddS )NrO   c                    s   t jt|  dS )NrO   )r-   rV   rN   rQ   rG   rJ   nr   r   rS     s   
ztensors.<locals>.<lambda>rU   )r   rX   rY   rG   rJ   r&   rZ   r   r   r   tensors  s    r   c              	   C   s   t | dd||||dS r\   )r   )r   r]   r^   rG   rJ   r   r   r   	tensors1d"  s          r   )device_typec                 C   s   g | ]}t jtj|d qS ))r   Z	device_id)r   DeviceOptionr   GpuDeviceType).0ir   r   r   
<listcomp>5  s   r   c                   C   s
   t tS N)r-   re   device_optionsr   r   r   r   device_checker_device_options:  s    r   c                   C   s
   t tS r   )r-   sampled_fromr   r   r   r   r   gradient_checker_device_option>  s    r   )gcdc   temp_wsc                 c   s0   t  }t | d d V  t   t | d S )NT)r   ZCurrentWorkspaceZSwitchWorkspaceZResetWorkspace)nameZold_ws_namer   r   r   temp_workspaceM  s
    r   c           
   	   C   s   t |}|j|  t }|j|g |jr8|jnd|_t	 b |pVt
|d }t|j|D ] \}}tj||||| d qdt| t|jd|d}	W 5 Q R X |	S )Ntestr   device_optionr0   T)copydeepcopyr   CopyFromr   ZNetDefopextendr   r   r   InferOpBlobDevicesAsDictzipinputr   FeedBlobr,   Z	CreateNetZBenchmarkNet)
r   r   inputsinput_device_optionsZ
iterationsnet_input_device_optionsr   bretr   r   r   runOpBenchmarkV  s$    


r   c              
   C   s   t |}|j|  t  t|jt|krBtd|j|f |pRt	|d }t
|j|D ] \}}tj||||| d q`t| ttt|j}g }|D ]"}	|j|	 }
t|
}|| q|W  5 Q R  S Q R X d S )N7must supply an input for each input on the op: %s vs %sr   r   )r   r   r   r   r   lenr   rE   r   r   r   r   r   r,   RunOperatorOncelistrangeoutput	FetchBlobrl   )r   r   r   r   r   r   r   outputs_to_checkoutsoutput_indexoutput_blob_namer   r   r   r   runOpOnInputq  s4    




r   c                   @   s^   e Zd ZdZdddZdd	d
ZdddZdddZdddZdddZ	de
fdfddZdS )HypothesisTestCasez
    A unittest.TestCase subclass with some helper functions for
    utilizing the `hypothesis` (hypothesis.readthedocs.io) library.
    N{Gz?c                 C   s(   t j||d}| ||||| dS )al  
        Asserts that the operator computes the same outputs, regardless of
        which device it is executed on.

        Useful for checking the consistency of GPU and CPU
        implementations of operators.

        Usage example:

            @given(inputs=hu.tensors(n=2), in_place=st.booleans(), **hu.gcs)
            def test_sum(self, inputs, in_place, gc, dc):
                op = core.CreateOperator("Sum", ["X1", "X2"],
                                                ["Y" if not in_place else "X1"])
                X1, X2 = inputs
                self.assertDeviceChecks(dc, op, [X1, X2], [0])
        )r   N)r   ZDeviceChecker
assertTrueCheckSimple)selfr   r   r   r   r   	thresholdr   r   r   r   assertDeviceChecks  s    z%HypothesisTestCase.assertDeviceChecks{Gzt?皙?Fc              	   C   sd   t j|||t||	d}|j||||||	|
d\}}}| |j|j | |dt|j|   dS )aj  
        Implements a standard numerical gradient checker for the operator
        in question.

        Useful for checking the consistency of the forward and
        backward implementations of operators.

        Usage example:

            @given(inputs=hu.tensors(n=2), in_place=st.booleans(), **hu.gcs)
            def test_sum(self, inputs, in_place, gc, dc):
                op = core.CreateOperator("Sum", ["X1", "X2"],
                                                ["Y" if not in_place else "X1"])
                X1, X2 = inputs
                self.assertGradientChecks(gc, op, [X1, X2], 0, [0])
        )stepsizer   r   Zworkspace_namer   )grad_opsr   ensure_outputs_are_inferredz Gradient check failed for input N)r   ZGradientCheckerstrr   assertEqualra   r   r   )r   r   r   r   r   Zoutputs_with_gradsr   r   r   r   r   r   resZgradZgrad_estimatedr   r   r   assertGradientChecks  s*       z'HypothesisTestCase.assertGradientChecks-C6?c              	   C   s  |d }t j|g||i\}}	t|}
||
||}t|t| t| | t|t| t	|j
|D ]\}}|	|}|s| | qrt|t jr|}d }|}n|\}}|j}tt|}tjj||||d|d |d k	rrtt|j}tjj||ddd qrd S )NZ_gradz2Gradient {0} (x) is not matching the reference (y)atolrtolerr_msgr   )r   r   )r   ZGradientRegistryZGetBackwardPassr   r   r   ZRunOperatorsOncer   r   r   r   r,   ZassertIsNone
isinstanceZBlobReferencevaluesr   r>   testingassert_allcloseformatindices)r   r   r   Zref_outputsoutput_to_gradgrad_referencer   Zgrad_blob_namer   Zgrad_mapZoutput_gradZgrad_ref_outputsr   refZ
grad_namesZref_valsZref_indicesZval_namevalsr   r   r   r   _assertGradReferenceChecks  sH    	 



 z-HypothesisTestCase._assertGradReferenceChecksc              
   C   s  |  | p||kd| ||kr(d S t|}t|tjkr|jtdkrZtj	j
}q|jtdkrttj	j}q|jtdkrtj	j}q|jtdkrtj	j}qdtj}ntt|}ztjjt|| tjt|jtjd||| |jd |tj	jkrW d S tjj|| |d	||| |d W nL tk
r } z,tt| td
dksz|r~|W 5 d }~X Y nX d S )NzShape for {0} was not inferredr@   r?   rA   rB   z
unknown {}zShape {} mismatch: {} vs. {})r   zType {} mismatch: {} vs. {}CAFFE2_ASSERT_SHAPEINFERENCEr   )r   r   r   r   typer>   ZndarrayrG   r   ZTensorProtoZDOUBLEFLOATZINT32ZINT64r   r   assert_array_equalrm   ZastyperA   ra   Zassert_equalrn   loggingwarningr
   r   )r   r   shapestypesr   ensure_output_is_inferredZcorrect_typeer   r   r   _assertInferTensorChecks  sV    




  
z+HypothesisTestCase._assertInferTensorChecksc                 C   sb  t |}|j| t : t|jt|krDtd|j|f |pTt	|d }t
|j|D ] \}}tj|||||d qbtd}| j|g d}zt|g\}}d}W nH tk
r } z(tt| tddks|r|W 5 d	}~X Y nX t| || }t|ts8t|ts8td
|
sf| t|t|j ttt|j}
g }t
|
|D ]\}}|j| }t |}|j!j"dkrt#j$%|| n*|	d	kr|}	t#j$j&|||	|d'|d |r| j(|||||d |)| qt|d	k	rH|d	k	st*dt+| | j,||||||d W 5 Q R X |W  5 Q R  S Q R X d	S )a  
        This runs the reference Python function implementation
        (effectively calling `reference(*inputs)`, and compares that
        to the output of output, with an absolute/relative tolerance
        given by the `threshold` parameter.

        Useful for checking the implementation matches the Python
        (typically NumPy) implementation of the same functionality.

        Usage example:

            @given(X=hu.tensor(), inplace=st.booleans(), **hu.gcs)
            def test_softsign(self, X, inplace, gc, dc):
                op = core.CreateOperator(
                    "Softsign", ["X"], ["X" if inplace else "Y"])

                def softsign(X):
                    return (X / (1 + np.abs(X)),)

                self.assertReferenceChecks(gc, op, [X], softsign)
        r   r   r   ZopnetFTr   r   NzlYou are providing a wrong reference implementation. A proper one should return a tuple/list of numpy arrays.)SOz(Output {0} is not matching the referencer   )r   z=If grad_reference is set,output_to_grad has to be set as well)r   )-r   r   r   r   r   r   r   rE   r   r   r   r   r   r,   ZNetZProtor   r   ZInferShapesAndTypesRuntimeErrorr   r   r   r
   r   
RunNetOncer   tupler   r   r   r   r   rG   kindr>   r   r   r   r   r   rl   rn   ZDeviceScoper   )r   r   r   r   	referencer   r   r   r   r   r   r   r   r   r   r   Ztest_shape_inferencer   r   r   Zreference_outputsr   r   r   r   r   r   r   r   assertReferenceChecksG  s    #







      
   z(HypothesisTestCase.assertReferenceChecksTc              	   C   s
  |r<t tt|jt|j t |jt |j ks<tdt|}|j	| t
  |pjt|d }t|j|D ] \}	}
tj|	|
||	|d qx|rt| t| dd |jD }|r|f ttt|jt|j ||  n|||d W 5 Q R X d S )Nz0in-place ops are not supported in as_kwargs moder   r   c                 S   s   g | ]}t |qS r   )r   r   )r   r   r   r   r   r     s     z=HypothesisTestCase.assertValidationChecks.<locals>.<listcomp>)r   outputs)r   setr   r   r   rn   r   r   r   r   r   r   r   r   r   r   r,   r   r   dict)r   r   r   r   Z	validatorr   Z	as_kwargsZinit_netr   r   r   r   r   r   r   assertValidationChecks  s8    




 
z)HypothesisTestCase.assertValidationChecksc           
   	   C   s   t |}|j| t r |p.t|d }t|j|D ] \}}	t	j
||	|||d q<|d krx| |t	j| n| ||t	j| W 5 Q R X d S )Nr   r   )r   r   r   r   r   r   r   r   r   r   r   r,   assertRaisesr   assertRaisesRegex)
r   r   r   r   r   	exceptionregexpr   r   r   r   r   r   assertRunOpRaises  s(    	

   z$HypothesisTestCase.assertRunOpRaises)Nr   )Nr   r   NF)r   )F)Nr   NNNNF)NTN)__name__
__module____qualname____doc__r   r   r   r   r   r   	Exceptionr   r   r   r   r   r     s<     
(     
7 
0 
6       
q   
)r   )r0   r8   )NN)NN)r   )Nr6   )N)Tr   Zcaffe2.protor   Zcaffe2.pythonr   r   r   r   r   
contextlibr   r~   r    Zhypothesis.extra.numpyZhypothesis.strategiesZ
strategiesr-   r   rM   r>   r
   r   r   r   r   r$   r.   Zregister_profileZHealthCheckZtoo_slowZ	VerbosityverboseZload_profiler   r;   r?   rI   rN   r[   r_   rj   rs   r}   r   rB   r   r   r   r   r   Zcpu_doZCUDAZcuda_doZHIPZhip_dor   Zgpu_doZhas_cuda_supportZ_cuda_do_listZhas_hip_supportZ_hip_do_listZhas_gpu_supportZ_gpu_do_listZ_device_options_no_hipr   r   ZNumGpuDevicesZexpanded_device_optionsr   r   r   Zgcsr   re   Zgcs_cpu_onlyZgcs_cuda_onlyZgcs_gpu_onlyZ
gcs_no_hipcontextmanagerr   r   r   ZTestCaser   r   r   r   r   <module>   s   &
	





   
	


  
 
 